@sanity/cli 6.3.2 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +16 -10
  2. package/dist/actions/init/bootstrapLocalTemplate.js +16 -1
  3. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  4. package/dist/actions/init/initApp.js +72 -0
  5. package/dist/actions/init/initApp.js.map +1 -0
  6. package/dist/actions/init/initHelpers.js +37 -0
  7. package/dist/actions/init/initHelpers.js.map +1 -0
  8. package/dist/actions/init/initNextJs.js +246 -0
  9. package/dist/actions/init/initNextJs.js.map +1 -0
  10. package/dist/actions/init/initStudio.js +127 -0
  11. package/dist/actions/init/initStudio.js.map +1 -0
  12. package/dist/actions/init/scaffoldTemplate.js +114 -0
  13. package/dist/actions/init/scaffoldTemplate.js.map +1 -0
  14. package/dist/actions/init/templates/appQuickstart.js +2 -1
  15. package/dist/actions/init/templates/appQuickstart.js.map +1 -1
  16. package/dist/actions/init/templates/appSanityUi.js +2 -1
  17. package/dist/actions/init/templates/appSanityUi.js.map +1 -1
  18. package/dist/actions/init/templates/shopify.js +6 -6
  19. package/dist/actions/init/templates/shopify.js.map +1 -1
  20. package/dist/actions/init/templates/shopifyOnline.js +2 -2
  21. package/dist/actions/init/templates/shopifyOnline.js.map +1 -1
  22. package/dist/actions/mcp/detectAvailableEditors.js +16 -3
  23. package/dist/actions/mcp/detectAvailableEditors.js.map +1 -1
  24. package/dist/actions/mcp/editorConfigs.js +192 -132
  25. package/dist/actions/mcp/editorConfigs.js.map +1 -1
  26. package/dist/actions/mcp/setupMCP.js +4 -1
  27. package/dist/actions/mcp/setupMCP.js.map +1 -1
  28. package/dist/actions/mcp/writeMCPConfig.js +2 -2
  29. package/dist/actions/mcp/writeMCPConfig.js.map +1 -1
  30. package/dist/actions/schema/extractSchema.js +5 -7
  31. package/dist/actions/schema/extractSchema.js.map +1 -1
  32. package/dist/commands/datasets/copy.js +14 -0
  33. package/dist/commands/datasets/copy.js.map +1 -1
  34. package/dist/commands/init.js +149 -482
  35. package/dist/commands/init.js.map +1 -1
  36. package/dist/commands/mcp/configure.js +1 -1
  37. package/dist/commands/mcp/configure.js.map +1 -1
  38. package/dist/hooks/prerun/injectEnvVariables.js +3 -5
  39. package/dist/hooks/prerun/injectEnvVariables.js.map +1 -1
  40. package/dist/services/datasets.js +2 -1
  41. package/dist/services/datasets.js.map +1 -1
  42. package/dist/telemetry/init.telemetry.js.map +1 -1
  43. package/dist/util/packageManager/installationInfo/detectPackages.js +13 -7
  44. package/dist/util/packageManager/installationInfo/detectPackages.js.map +1 -1
  45. package/dist/util/update/fetchUpdateInfo.js +40 -0
  46. package/dist/util/update/fetchUpdateInfo.js.map +1 -0
  47. package/dist/util/update/fetchUpdateInfo.worker.js +19 -0
  48. package/dist/util/update/fetchUpdateInfo.worker.js.map +1 -0
  49. package/dist/util/update/getRunnerUpdateCommand.js +33 -0
  50. package/dist/util/update/getRunnerUpdateCommand.js.map +1 -0
  51. package/dist/util/update/getUpdateCommand.js +6 -7
  52. package/dist/util/update/getUpdateCommand.js.map +1 -1
  53. package/dist/util/update/packageRunner.js +10 -0
  54. package/dist/util/update/packageRunner.js.map +1 -0
  55. package/dist/util/update/resolveRunnerPackage.js +45 -0
  56. package/dist/util/update/resolveRunnerPackage.js.map +1 -0
  57. package/dist/util/update/resolveUpdateTarget.js +31 -0
  58. package/dist/util/update/resolveUpdateTarget.js.map +1 -0
  59. package/dist/util/update/showNotificationUpdate.js +8 -6
  60. package/dist/util/update/showNotificationUpdate.js.map +1 -1
  61. package/dist/util/update/updateChecker.js +73 -38
  62. package/dist/util/update/updateChecker.js.map +1 -1
  63. package/oclif.manifest.json +540 -525
  64. package/package.json +6 -6
  65. package/templates/app-quickstart/src/App.tsx +2 -2
  66. package/templates/app-sanity-ui/src/App.tsx +2 -2
  67. package/templates/shopify/schemaTypes/objects/hotspot/imageWithProductHotspotsType.ts +1 -1
  68. package/dist/util/update/fetchLatestVersion.js +0 -21
  69. package/dist/util/update/fetchLatestVersion.js.map +0 -1
package/README.md CHANGED
@@ -907,20 +907,21 @@ Copy a dataset or manage copy jobs
907
907
 
908
908
  ```
909
909
  USAGE
910
- $ sanity datasets copy [SOURCE] [TARGET] [-p <id>] [--attach <value> | --list | --detach | --skip-history]
911
- [--limit <value> ] [--offset <value> ]
910
+ $ sanity datasets copy [SOURCE] [TARGET] [-p <id>] [--limit <value> ] [--offset <value> ]
911
+ [--skip-content-releases | | [--attach <value> | --list | --detach | --skip-history]]
912
912
 
913
913
  ARGUMENTS
914
914
  [SOURCE] Name of the dataset to copy from
915
915
  [TARGET] Name of the dataset to copy to
916
916
 
917
917
  FLAGS
918
- --attach=<value> Attach to the running copy process to show progress
919
- --detach Start the copy without waiting for it to finish
920
- --limit=<value> Maximum number of jobs returned (default 10, max 1000)
921
- --list Lists all dataset copy jobs
922
- --offset=<value> Start position in the list of jobs (default 0)
923
- --skip-history Don't preserve document history on copy
918
+ --attach=<value> Attach to the running copy process to show progress
919
+ --detach Start the copy without waiting for it to finish
920
+ --limit=<value> Maximum number of jobs returned (default 10, max 1000)
921
+ --list Lists all dataset copy jobs
922
+ --offset=<value> Start position in the list of jobs (default 0)
923
+ --skip-content-releases Don't copy content release documents to the target dataset
924
+ --skip-history Don't preserve document history on copy
924
925
 
925
926
  OVERRIDE FLAGS
926
927
  -p, --project-id=<id> Project ID to copy dataset in (overrides CLI configuration)
@@ -945,6 +946,10 @@ EXAMPLES
945
946
 
946
947
  $ sanity datasets copy --skip-history source target
947
948
 
949
+ Copy without content release documents
950
+
951
+ $ sanity datasets copy --skip-content-releases source target
952
+
948
953
  Start copy job without waiting for completion
949
954
 
950
955
  $ sanity datasets copy --detach source target
@@ -2467,14 +2472,15 @@ EXAMPLES
2467
2472
 
2468
2473
  ## `sanity mcp configure`
2469
2474
 
2470
- Configure Sanity MCP server for AI editors (Claude Code, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, VS Code)
2475
+ Configure Sanity MCP server for AI editors (Antigravity, Claude Code, Cline, Cline CLI, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, MCPorter, OpenCode, VS Code, VS Code Insiders, Zed)
2471
2476
 
2472
2477
  ```
2473
2478
  USAGE
2474
2479
  $ sanity mcp configure
2475
2480
 
2476
2481
  DESCRIPTION
2477
- Configure Sanity MCP server for AI editors (Claude Code, Codex CLI, Cursor, Gemini CLI, GitHub Copilot CLI, VS Code)
2482
+ Configure Sanity MCP server for AI editors (Antigravity, Claude Code, Cline, Cline CLI, Codex CLI, Cursor, Gemini CLI,
2483
+ GitHub Copilot CLI, MCPorter, OpenCode, VS Code, VS Code Insiders, Zed)
2478
2484
 
2479
2485
  EXAMPLES
2480
2486
  Configure Sanity MCP server for detected AI editors
@@ -11,6 +11,7 @@ import { createCliConfig } from './createCliConfig.js';
11
11
  import { createPackageManifest } from './createPackageManifest.js';
12
12
  import { createStudioConfig } from './createStudioConfig.js';
13
13
  import { determineAppTemplate } from './determineAppTemplate.js';
14
+ import { processTemplate } from './processTemplate.js';
14
15
  import { sdkAppDependencies } from './sdkAppDependencies.js';
15
16
  import { studioDependencies } from './studioDependencies.js';
16
17
  import templates from './templates/index.js';
@@ -44,6 +45,18 @@ export async function bootstrapLocalTemplate(opts) {
44
45
  await fs.copyFile(path.join(sharedDir, 'tsconfig.json'), path.join(outputPath, 'tsconfig.json'));
45
46
  }
46
47
  spin.succeed();
48
+ if (isAppTemplate) {
49
+ const appEntryPath = path.join(outputPath, 'src', 'App.tsx');
50
+ const raw = await fs.readFile(appEntryPath, 'utf8');
51
+ const rendered = processTemplate({
52
+ template: raw,
53
+ variables: {
54
+ dataset: variables.dataset ?? '',
55
+ projectId: variables.projectId ?? ''
56
+ }
57
+ });
58
+ await fs.writeFile(appEntryPath, rendered);
59
+ }
47
60
  // Merge global and template-specific plugins and dependencies
48
61
  // Resolve latest versions of Sanity-dependencies
49
62
  spin = spinner('Resolving latest module versions').start();
@@ -108,7 +121,9 @@ export async function bootstrapLocalTemplate(opts) {
108
121
  writeFileIfNotExists('eslint.config.mjs', `import studio from '@sanity/eslint-config-studio'\n\nexport default [...studio]\n`)
109
122
  ].filter(Boolean));
110
123
  debug('Updating initial template metadata');
111
- await updateInitialTemplateMetadata(variables.projectId, `cli-${templateName}`);
124
+ if (variables.projectId) {
125
+ await updateInitialTemplateMetadata(variables.projectId, `cli-${templateName}`);
126
+ }
112
127
  // Finish up by providing init process with template-specific info
113
128
  spin.succeed();
114
129
  return template;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/init/bootstrapLocalTemplate.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Output, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport deburr from 'lodash-es/deburr.js'\n\nimport {copy} from '../../util/copy.js'\nimport {resolveLatestVersions} from '../../util/resolveLatestVersions.js'\nimport {createAppCliConfig} from './createAppCliConfig.js'\nimport {createCliConfig} from './createCliConfig.js'\nimport {createPackageManifest} from './createPackageManifest.js'\nimport {createStudioConfig, type GenerateConfigOptions} from './createStudioConfig.js'\nimport {determineAppTemplate} from './determineAppTemplate.js'\nimport {sdkAppDependencies} from './sdkAppDependencies.js'\nimport {studioDependencies} from './studioDependencies.js'\nimport templates from './templates/index.js'\nimport {type ProjectTemplate} from './types.js'\nimport {updateInitialTemplateMetadata} from './updateInitialTemplateMetadata.js'\n\nconst debug = subdebug('init:bootstrapRemoteTemplate')\n\ninterface BootstrapLocalOptions {\n output: Output\n outputPath: string\n packageName: string\n templateName: string\n useTypeScript: boolean\n variables: GenerateConfigOptions['variables']\n\n overwriteFiles?: boolean\n}\n\nexport async function bootstrapLocalTemplate(\n opts: BootstrapLocalOptions,\n): Promise<ProjectTemplate> {\n const {output, outputPath, packageName, templateName, useTypeScript, variables} = opts\n // packages/@sanity/cli/src/actions/init/ -> packages/@sanity/cli/src/action -> packages/@sanity/cli/src/\n const cliRoot = path.resolve(import.meta.dirname, '../../..')\n const templatesDir = path.join(cliRoot, 'templates')\n const sourceDir = path.join(templatesDir, templateName)\n const sharedDir = path.join(templatesDir, 'shared')\n const isAppTemplate = determineAppTemplate(templateName)\n\n // Check that we have a template info file (dependencies, plugins etc)\n const template = templates[templateName]\n if (!template) {\n throw new Error(`Template \"${templateName}\" not defined`)\n }\n\n // Copy template files\n debug('Copying files from template \"%s\" to \"%s\"', templateName, outputPath)\n let spin = spinner('Bootstrapping files from template').start()\n\n debug(`Copying template from : ${sourceDir}`)\n await copy(sourceDir, outputPath, {\n rename: useTypeScript ? toTypeScriptPath : undefined,\n })\n debug(`Copying shared template code from : ${sharedDir}`)\n await copy(path.join(sharedDir, 'gitignore.txt'), outputPath, {rename: () => '.gitignore'})\n\n if (useTypeScript) {\n await fs.copyFile(path.join(sharedDir, 'tsconfig.json'), path.join(outputPath, 'tsconfig.json'))\n }\n\n spin.succeed()\n\n // Merge global and template-specific plugins and dependencies\n\n // Resolve latest versions of Sanity-dependencies\n spin = spinner('Resolving latest module versions').start()\n const dependencyVersions = await resolveLatestVersions({\n ...(isAppTemplate ? sdkAppDependencies.dependencies : studioDependencies.dependencies),\n ...(isAppTemplate ? sdkAppDependencies.devDependencies : studioDependencies.devDependencies),\n ...template.dependencies,\n ...template.devDependencies,\n })\n spin.succeed()\n\n // Use the resolved version for the given dependency\n const dependencies: Record<string, string> = {}\n for (const dependency of Object.keys({\n ...(isAppTemplate ? sdkAppDependencies.dependencies : studioDependencies.dependencies),\n ...template.dependencies,\n })) {\n dependencies[dependency] = dependencyVersions[dependency]\n }\n\n const devDependencies: Record<string, string> = {}\n for (const dependency of Object.keys({\n ...(isAppTemplate ? sdkAppDependencies.devDependencies : studioDependencies.devDependencies),\n ...template.devDependencies,\n })) {\n devDependencies[dependency] = dependencyVersions[dependency]\n }\n\n let packageJsonName: string = packageName\n\n /**\n * Currently app init doesn't ask for a name, so we use the last part of the path\n */\n if (isAppTemplate) {\n packageJsonName = deburr(path.basename(outputPath).toLowerCase())\n .replaceAll(/\\s+/g, '-')\n .replaceAll(/[^a-z0-9-]/g, '')\n }\n\n // Now create a package manifest (`package.json`) with the merged dependencies\n spin = spinner('Creating default project files').start()\n const packageManifest = createPackageManifest({\n dependencies,\n devDependencies,\n isAppTemplate,\n name: packageJsonName,\n scripts: template.scripts,\n type: template.type,\n })\n\n // ...and a studio config (`sanity.config.[ts|js]`)\n const studioConfig = createStudioConfig({\n template: template.configTemplate,\n variables,\n })\n\n // ...and a CLI config (`sanity.cli.[ts|js]`)\n const cliConfig = isAppTemplate\n ? createAppCliConfig({\n entry: template.entry!,\n organizationId: variables.organizationId,\n })\n : createCliConfig({\n autoUpdates: variables.autoUpdates,\n dataset: variables.dataset,\n projectId: variables.projectId,\n })\n\n // Write non-template files to disc\n const codeExt = useTypeScript ? 'ts' : 'js'\n await Promise.all(\n [\n isAppTemplate\n ? Promise.resolve(null)\n : writeFileIfNotExists(`sanity.config.${codeExt}`, studioConfig),\n writeFileIfNotExists(`sanity.cli.${codeExt}`, cliConfig),\n writeFileIfNotExists('package.json', packageManifest),\n\n writeFileIfNotExists(\n 'eslint.config.mjs',\n `import studio from '@sanity/eslint-config-studio'\\n\\nexport default [...studio]\\n`,\n ),\n ].filter(Boolean),\n )\n\n debug('Updating initial template metadata')\n await updateInitialTemplateMetadata(variables.projectId, `cli-${templateName}`)\n\n // Finish up by providing init process with template-specific info\n spin.succeed()\n return template\n\n async function writeFileIfNotExists(fileName: string, content: string): Promise<void> {\n const filePath = path.join(outputPath, fileName)\n\n if (opts.overwriteFiles) {\n // If overwrite is enabled, just write the file\n await fs.writeFile(filePath, content)\n return\n }\n\n try {\n await fs.writeFile(filePath, content, {flag: 'wx'})\n } catch (err) {\n if (err.code === 'EEXIST') {\n output.warn(`\\n${styleText('yellow', '⚠')} File \"${filePath}\" already exists, skipping`)\n } else {\n throw err\n }\n }\n }\n}\n\nfunction toTypeScriptPath(originalPath: string): string {\n return originalPath.replace(/\\.js$/, '.ts')\n}\n"],"names":["fs","path","styleText","subdebug","spinner","deburr","copy","resolveLatestVersions","createAppCliConfig","createCliConfig","createPackageManifest","createStudioConfig","determineAppTemplate","sdkAppDependencies","studioDependencies","templates","updateInitialTemplateMetadata","debug","bootstrapLocalTemplate","opts","output","outputPath","packageName","templateName","useTypeScript","variables","cliRoot","resolve","dirname","templatesDir","join","sourceDir","sharedDir","isAppTemplate","template","Error","spin","start","rename","toTypeScriptPath","undefined","copyFile","succeed","dependencyVersions","dependencies","devDependencies","dependency","Object","keys","packageJsonName","basename","toLowerCase","replaceAll","packageManifest","name","scripts","type","studioConfig","configTemplate","cliConfig","entry","organizationId","autoUpdates","dataset","projectId","codeExt","Promise","all","writeFileIfNotExists","filter","Boolean","fileName","content","filePath","overwriteFiles","writeFile","flag","err","code","warn","originalPath","replace"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/init/bootstrapLocalTemplate.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Output, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport deburr from 'lodash-es/deburr.js'\n\nimport {copy} from '../../util/copy.js'\nimport {resolveLatestVersions} from '../../util/resolveLatestVersions.js'\nimport {createAppCliConfig} from './createAppCliConfig.js'\nimport {createCliConfig} from './createCliConfig.js'\nimport {createPackageManifest} from './createPackageManifest.js'\nimport {createStudioConfig, type GenerateConfigOptions} from './createStudioConfig.js'\nimport {determineAppTemplate} from './determineAppTemplate.js'\nimport {processTemplate} from './processTemplate.js'\nimport {sdkAppDependencies} from './sdkAppDependencies.js'\nimport {studioDependencies} from './studioDependencies.js'\nimport templates from './templates/index.js'\nimport {type ProjectTemplate} from './types.js'\nimport {updateInitialTemplateMetadata} from './updateInitialTemplateMetadata.js'\n\nconst debug = subdebug('init:bootstrapRemoteTemplate')\n\ninterface BootstrapLocalOptions {\n output: Output\n outputPath: string\n packageName: string\n templateName: string\n useTypeScript: boolean\n variables: GenerateConfigOptions['variables']\n\n overwriteFiles?: boolean\n}\n\nexport async function bootstrapLocalTemplate(\n opts: BootstrapLocalOptions,\n): Promise<ProjectTemplate> {\n const {output, outputPath, packageName, templateName, useTypeScript, variables} = opts\n // packages/@sanity/cli/src/actions/init/ -> packages/@sanity/cli/src/action -> packages/@sanity/cli/src/\n const cliRoot = path.resolve(import.meta.dirname, '../../..')\n const templatesDir = path.join(cliRoot, 'templates')\n const sourceDir = path.join(templatesDir, templateName)\n const sharedDir = path.join(templatesDir, 'shared')\n const isAppTemplate = determineAppTemplate(templateName)\n\n // Check that we have a template info file (dependencies, plugins etc)\n const template = templates[templateName]\n if (!template) {\n throw new Error(`Template \"${templateName}\" not defined`)\n }\n\n // Copy template files\n debug('Copying files from template \"%s\" to \"%s\"', templateName, outputPath)\n let spin = spinner('Bootstrapping files from template').start()\n\n debug(`Copying template from : ${sourceDir}`)\n await copy(sourceDir, outputPath, {\n rename: useTypeScript ? toTypeScriptPath : undefined,\n })\n debug(`Copying shared template code from : ${sharedDir}`)\n await copy(path.join(sharedDir, 'gitignore.txt'), outputPath, {rename: () => '.gitignore'})\n\n if (useTypeScript) {\n await fs.copyFile(path.join(sharedDir, 'tsconfig.json'), path.join(outputPath, 'tsconfig.json'))\n }\n\n spin.succeed()\n\n if (isAppTemplate) {\n const appEntryPath = path.join(outputPath, 'src', 'App.tsx')\n const raw = await fs.readFile(appEntryPath, 'utf8')\n const rendered = processTemplate({\n template: raw,\n variables: {\n dataset: variables.dataset ?? '',\n projectId: variables.projectId ?? '',\n },\n })\n await fs.writeFile(appEntryPath, rendered)\n }\n\n // Merge global and template-specific plugins and dependencies\n\n // Resolve latest versions of Sanity-dependencies\n spin = spinner('Resolving latest module versions').start()\n const dependencyVersions = await resolveLatestVersions({\n ...(isAppTemplate ? sdkAppDependencies.dependencies : studioDependencies.dependencies),\n ...(isAppTemplate ? sdkAppDependencies.devDependencies : studioDependencies.devDependencies),\n ...template.dependencies,\n ...template.devDependencies,\n })\n spin.succeed()\n\n // Use the resolved version for the given dependency\n const dependencies: Record<string, string> = {}\n for (const dependency of Object.keys({\n ...(isAppTemplate ? sdkAppDependencies.dependencies : studioDependencies.dependencies),\n ...template.dependencies,\n })) {\n dependencies[dependency] = dependencyVersions[dependency]\n }\n\n const devDependencies: Record<string, string> = {}\n for (const dependency of Object.keys({\n ...(isAppTemplate ? sdkAppDependencies.devDependencies : studioDependencies.devDependencies),\n ...template.devDependencies,\n })) {\n devDependencies[dependency] = dependencyVersions[dependency]\n }\n\n let packageJsonName: string = packageName\n\n /**\n * Currently app init doesn't ask for a name, so we use the last part of the path\n */\n if (isAppTemplate) {\n packageJsonName = deburr(path.basename(outputPath).toLowerCase())\n .replaceAll(/\\s+/g, '-')\n .replaceAll(/[^a-z0-9-]/g, '')\n }\n\n // Now create a package manifest (`package.json`) with the merged dependencies\n spin = spinner('Creating default project files').start()\n const packageManifest = createPackageManifest({\n dependencies,\n devDependencies,\n isAppTemplate,\n name: packageJsonName,\n scripts: template.scripts,\n type: template.type,\n })\n\n // ...and a studio config (`sanity.config.[ts|js]`)\n const studioConfig = createStudioConfig({\n template: template.configTemplate,\n variables,\n })\n\n // ...and a CLI config (`sanity.cli.[ts|js]`)\n const cliConfig = isAppTemplate\n ? createAppCliConfig({\n entry: template.entry!,\n organizationId: variables.organizationId,\n })\n : createCliConfig({\n autoUpdates: variables.autoUpdates,\n dataset: variables.dataset,\n projectId: variables.projectId,\n })\n\n // Write non-template files to disc\n const codeExt = useTypeScript ? 'ts' : 'js'\n await Promise.all(\n [\n isAppTemplate\n ? Promise.resolve(null)\n : writeFileIfNotExists(`sanity.config.${codeExt}`, studioConfig),\n writeFileIfNotExists(`sanity.cli.${codeExt}`, cliConfig),\n writeFileIfNotExists('package.json', packageManifest),\n\n writeFileIfNotExists(\n 'eslint.config.mjs',\n `import studio from '@sanity/eslint-config-studio'\\n\\nexport default [...studio]\\n`,\n ),\n ].filter(Boolean),\n )\n\n debug('Updating initial template metadata')\n if (variables.projectId) {\n await updateInitialTemplateMetadata(variables.projectId, `cli-${templateName}`)\n }\n\n // Finish up by providing init process with template-specific info\n spin.succeed()\n return template\n\n async function writeFileIfNotExists(fileName: string, content: string): Promise<void> {\n const filePath = path.join(outputPath, fileName)\n\n if (opts.overwriteFiles) {\n // If overwrite is enabled, just write the file\n await fs.writeFile(filePath, content)\n return\n }\n\n try {\n await fs.writeFile(filePath, content, {flag: 'wx'})\n } catch (err) {\n if (err.code === 'EEXIST') {\n output.warn(`\\n${styleText('yellow', '⚠')} File \"${filePath}\" already exists, skipping`)\n } else {\n throw err\n }\n }\n }\n}\n\nfunction toTypeScriptPath(originalPath: string): string {\n return originalPath.replace(/\\.js$/, '.ts')\n}\n"],"names":["fs","path","styleText","subdebug","spinner","deburr","copy","resolveLatestVersions","createAppCliConfig","createCliConfig","createPackageManifest","createStudioConfig","determineAppTemplate","processTemplate","sdkAppDependencies","studioDependencies","templates","updateInitialTemplateMetadata","debug","bootstrapLocalTemplate","opts","output","outputPath","packageName","templateName","useTypeScript","variables","cliRoot","resolve","dirname","templatesDir","join","sourceDir","sharedDir","isAppTemplate","template","Error","spin","start","rename","toTypeScriptPath","undefined","copyFile","succeed","appEntryPath","raw","readFile","rendered","dataset","projectId","writeFile","dependencyVersions","dependencies","devDependencies","dependency","Object","keys","packageJsonName","basename","toLowerCase","replaceAll","packageManifest","name","scripts","type","studioConfig","configTemplate","cliConfig","entry","organizationId","autoUpdates","codeExt","Promise","all","writeFileIfNotExists","filter","Boolean","fileName","content","filePath","overwriteFiles","flag","err","code","warn","originalPath","replace"],"mappings":"AAAA,OAAOA,QAAQ,mBAAkB;AACjC,OAAOC,UAAU,YAAW;AAC5B,SAAQC,SAAS,QAAO,YAAW;AAEnC,SAAgBC,QAAQ,QAAO,mBAAkB;AACjD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,OAAOC,YAAY,sBAAqB;AAExC,SAAQC,IAAI,QAAO,qBAAoB;AACvC,SAAQC,qBAAqB,QAAO,sCAAqC;AACzE,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,eAAe,QAAO,uBAAsB;AACpD,SAAQC,qBAAqB,QAAO,6BAA4B;AAChE,SAAQC,kBAAkB,QAAmC,0BAAyB;AACtF,SAAQC,oBAAoB,QAAO,4BAA2B;AAC9D,SAAQC,eAAe,QAAO,uBAAsB;AACpD,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,OAAOC,eAAe,uBAAsB;AAE5C,SAAQC,6BAA6B,QAAO,qCAAoC;AAEhF,MAAMC,QAAQf,SAAS;AAavB,OAAO,eAAegB,uBACpBC,IAA2B;IAE3B,MAAM,EAACC,MAAM,EAAEC,UAAU,EAAEC,WAAW,EAAEC,YAAY,EAAEC,aAAa,EAAEC,SAAS,EAAC,GAAGN;IAClF,yGAAyG;IACzG,MAAMO,UAAU1B,KAAK2B,OAAO,CAAC,YAAYC,OAAO,EAAE;IAClD,MAAMC,eAAe7B,KAAK8B,IAAI,CAACJ,SAAS;IACxC,MAAMK,YAAY/B,KAAK8B,IAAI,CAACD,cAAcN;IAC1C,MAAMS,YAAYhC,KAAK8B,IAAI,CAACD,cAAc;IAC1C,MAAMI,gBAAgBtB,qBAAqBY;IAE3C,sEAAsE;IACtE,MAAMW,WAAWnB,SAAS,CAACQ,aAAa;IACxC,IAAI,CAACW,UAAU;QACb,MAAM,IAAIC,MAAM,CAAC,UAAU,EAAEZ,aAAa,aAAa,CAAC;IAC1D;IAEA,sBAAsB;IACtBN,MAAM,4CAA4CM,cAAcF;IAChE,IAAIe,OAAOjC,QAAQ,qCAAqCkC,KAAK;IAE7DpB,MAAM,CAAC,wBAAwB,EAAEc,WAAW;IAC5C,MAAM1B,KAAK0B,WAAWV,YAAY;QAChCiB,QAAQd,gBAAgBe,mBAAmBC;IAC7C;IACAvB,MAAM,CAAC,oCAAoC,EAAEe,WAAW;IACxD,MAAM3B,KAAKL,KAAK8B,IAAI,CAACE,WAAW,kBAAkBX,YAAY;QAACiB,QAAQ,IAAM;IAAY;IAEzF,IAAId,eAAe;QACjB,MAAMzB,GAAG0C,QAAQ,CAACzC,KAAK8B,IAAI,CAACE,WAAW,kBAAkBhC,KAAK8B,IAAI,CAACT,YAAY;IACjF;IAEAe,KAAKM,OAAO;IAEZ,IAAIT,eAAe;QACjB,MAAMU,eAAe3C,KAAK8B,IAAI,CAACT,YAAY,OAAO;QAClD,MAAMuB,MAAM,MAAM7C,GAAG8C,QAAQ,CAACF,cAAc;QAC5C,MAAMG,WAAWlC,gBAAgB;YAC/BsB,UAAUU;YACVnB,WAAW;gBACTsB,SAAStB,UAAUsB,OAAO,IAAI;gBAC9BC,WAAWvB,UAAUuB,SAAS,IAAI;YACpC;QACF;QACA,MAAMjD,GAAGkD,SAAS,CAACN,cAAcG;IACnC;IAEA,8DAA8D;IAE9D,iDAAiD;IACjDV,OAAOjC,QAAQ,oCAAoCkC,KAAK;IACxD,MAAMa,qBAAqB,MAAM5C,sBAAsB;QACrD,GAAI2B,gBAAgBpB,mBAAmBsC,YAAY,GAAGrC,mBAAmBqC,YAAY;QACrF,GAAIlB,gBAAgBpB,mBAAmBuC,eAAe,GAAGtC,mBAAmBsC,eAAe;QAC3F,GAAGlB,SAASiB,YAAY;QACxB,GAAGjB,SAASkB,eAAe;IAC7B;IACAhB,KAAKM,OAAO;IAEZ,oDAAoD;IACpD,MAAMS,eAAuC,CAAC;IAC9C,KAAK,MAAME,cAAcC,OAAOC,IAAI,CAAC;QACnC,GAAItB,gBAAgBpB,mBAAmBsC,YAAY,GAAGrC,mBAAmBqC,YAAY;QACrF,GAAGjB,SAASiB,YAAY;IAC1B,GAAI;QACFA,YAAY,CAACE,WAAW,GAAGH,kBAAkB,CAACG,WAAW;IAC3D;IAEA,MAAMD,kBAA0C,CAAC;IACjD,KAAK,MAAMC,cAAcC,OAAOC,IAAI,CAAC;QACnC,GAAItB,gBAAgBpB,mBAAmBuC,eAAe,GAAGtC,mBAAmBsC,eAAe;QAC3F,GAAGlB,SAASkB,eAAe;IAC7B,GAAI;QACFA,eAAe,CAACC,WAAW,GAAGH,kBAAkB,CAACG,WAAW;IAC9D;IAEA,IAAIG,kBAA0BlC;IAE9B;;GAEC,GACD,IAAIW,eAAe;QACjBuB,kBAAkBpD,OAAOJ,KAAKyD,QAAQ,CAACpC,YAAYqC,WAAW,IAC3DC,UAAU,CAAC,QAAQ,KACnBA,UAAU,CAAC,eAAe;IAC/B;IAEA,8EAA8E;IAC9EvB,OAAOjC,QAAQ,kCAAkCkC,KAAK;IACtD,MAAMuB,kBAAkBnD,sBAAsB;QAC5C0C;QACAC;QACAnB;QACA4B,MAAML;QACNM,SAAS5B,SAAS4B,OAAO;QACzBC,MAAM7B,SAAS6B,IAAI;IACrB;IAEA,mDAAmD;IACnD,MAAMC,eAAetD,mBAAmB;QACtCwB,UAAUA,SAAS+B,cAAc;QACjCxC;IACF;IAEA,6CAA6C;IAC7C,MAAMyC,YAAYjC,gBACd1B,mBAAmB;QACjB4D,OAAOjC,SAASiC,KAAK;QACrBC,gBAAgB3C,UAAU2C,cAAc;IAC1C,KACA5D,gBAAgB;QACd6D,aAAa5C,UAAU4C,WAAW;QAClCtB,SAAStB,UAAUsB,OAAO;QAC1BC,WAAWvB,UAAUuB,SAAS;IAChC;IAEJ,mCAAmC;IACnC,MAAMsB,UAAU9C,gBAAgB,OAAO;IACvC,MAAM+C,QAAQC,GAAG,CACf;QACEvC,gBACIsC,QAAQ5C,OAAO,CAAC,QAChB8C,qBAAqB,CAAC,cAAc,EAAEH,SAAS,EAAEN;QACrDS,qBAAqB,CAAC,WAAW,EAAEH,SAAS,EAAEJ;QAC9CO,qBAAqB,gBAAgBb;QAErCa,qBACE,qBACA,CAAC,iFAAiF,CAAC;KAEtF,CAACC,MAAM,CAACC;IAGX1D,MAAM;IACN,IAAIQ,UAAUuB,SAAS,EAAE;QACvB,MAAMhC,8BAA8BS,UAAUuB,SAAS,EAAE,CAAC,IAAI,EAAEzB,cAAc;IAChF;IAEA,kEAAkE;IAClEa,KAAKM,OAAO;IACZ,OAAOR;IAEP,eAAeuC,qBAAqBG,QAAgB,EAAEC,OAAe;QACnE,MAAMC,WAAW9E,KAAK8B,IAAI,CAACT,YAAYuD;QAEvC,IAAIzD,KAAK4D,cAAc,EAAE;YACvB,+CAA+C;YAC/C,MAAMhF,GAAGkD,SAAS,CAAC6B,UAAUD;YAC7B;QACF;QAEA,IAAI;YACF,MAAM9E,GAAGkD,SAAS,CAAC6B,UAAUD,SAAS;gBAACG,MAAM;YAAI;QACnD,EAAE,OAAOC,KAAK;YACZ,IAAIA,IAAIC,IAAI,KAAK,UAAU;gBACzB9D,OAAO+D,IAAI,CAAC,CAAC,EAAE,EAAElF,UAAU,UAAU,KAAK,OAAO,EAAE6E,SAAS,0BAA0B,CAAC;YACzF,OAAO;gBACL,MAAMG;YACR;QACF;IACF;AACF;AAEA,SAAS1C,iBAAiB6C,YAAoB;IAC5C,OAAOA,aAAaC,OAAO,CAAC,SAAS;AACvC"}
@@ -0,0 +1,72 @@
1
+ import { styleText } from 'node:util';
2
+ import { logSymbols } from '@sanity/cli-core/ux';
3
+ import { getPostInitMCPPrompt } from './initHelpers.js';
4
+ import { scaffoldAndInstall, selectTemplate } from './scaffoldTemplate.js';
5
+ export async function initApp({ autoUpdates, datasetName, defaults, error, git, mcpConfigured, noGit, organizationId, output, outputPath, overwriteFiles, packageManager, projectId, remoteTemplateInfo, sluggedName, template, templateToken, trace, typescript, unattended, workDir }) {
6
+ const { template: resolvedTemplate, templateName, useTypeScript } = await selectTemplate({
7
+ remoteTemplateInfo,
8
+ template,
9
+ trace,
10
+ typescript,
11
+ unattended
12
+ });
13
+ if (!remoteTemplateInfo && !resolvedTemplate) {
14
+ error(`Template "${templateName}" not found`, {
15
+ exit: 1
16
+ });
17
+ }
18
+ await scaffoldAndInstall({
19
+ autoUpdates,
20
+ datasetName,
21
+ defaults,
22
+ displayName: '',
23
+ git,
24
+ noGit,
25
+ organizationId,
26
+ output,
27
+ outputPath,
28
+ overwriteFiles,
29
+ packageManager,
30
+ projectId,
31
+ remoteTemplateInfo,
32
+ sluggedName,
33
+ templateName,
34
+ templateToken,
35
+ trace,
36
+ unattended,
37
+ useTypeScript,
38
+ workDir
39
+ });
40
+ const isCurrentDir = outputPath === process.cwd();
41
+ const goToProjectDir = `\n(${styleText('cyan', `cd ${outputPath}`)} to navigate to your new project directory)`;
42
+ //output for custom apps here
43
+ output.log(`${logSymbols.success} ${styleText([
44
+ 'green',
45
+ 'bold'
46
+ ], 'Success!')} Your custom app has been scaffolded.`);
47
+ if (!isCurrentDir) output.log(goToProjectDir);
48
+ if (projectId && datasetName) {
49
+ output.log(`\nConfigured with project ${styleText('cyan', projectId)} and dataset ${styleText('cyan', datasetName)}.`);
50
+ output.log('Edit `src/App.tsx` to change these values or add more project / dataset pairs to your config.');
51
+ } else {
52
+ output.log(`\n${styleText('bold', 'Next')}, configure the project(s) and dataset(s) your app should work with in \`src/App.tsx\`.`);
53
+ }
54
+ output.log('\nRefer to our documentation for a walkthrough:');
55
+ output.log(styleText([
56
+ 'blue',
57
+ 'underline'
58
+ ], 'https://www.sanity.io/docs/app-sdk/sdk-configuration'));
59
+ if (mcpConfigured && mcpConfigured.length > 0) {
60
+ const message = await getPostInitMCPPrompt(mcpConfigured);
61
+ output.log(`\n${message}`);
62
+ output.log(`\nLearn more: ${styleText('cyan', 'https://mcp.sanity.io')}`);
63
+ output.log(`\nHave feedback? Tell us in the community: ${styleText('cyan', 'https://www.sanity.io/community/join')}`);
64
+ }
65
+ output.log('\n');
66
+ output.log(`Other helpful commands:`);
67
+ output.log(`npx sanity docs browse to open the documentation in a browser`);
68
+ output.log(`npx sanity dev to start the development server for your app`);
69
+ output.log(`npx sanity deploy to deploy your app`);
70
+ }
71
+
72
+ //# sourceMappingURL=initApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/init/initApp.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {type Output, type TelemetryUserProperties} from '@sanity/cli-core'\nimport {logSymbols} from '@sanity/cli-core/ux'\nimport {type TelemetryTrace} from '@sanity/telemetry'\n\nimport {type InitStepResult} from '../../telemetry/init.telemetry.js'\nimport {type EditorName} from '../mcp/editorConfigs.js'\nimport {getPostInitMCPPrompt} from './initHelpers.js'\nimport {type RepoInfo} from './remoteTemplate.js'\nimport {scaffoldAndInstall, selectTemplate} from './scaffoldTemplate.js'\n\nexport async function initApp({\n autoUpdates,\n datasetName,\n defaults,\n error,\n git,\n mcpConfigured,\n noGit,\n organizationId,\n output,\n outputPath,\n overwriteFiles,\n packageManager,\n projectId,\n remoteTemplateInfo,\n sluggedName,\n template,\n templateToken,\n trace,\n typescript,\n unattended,\n workDir,\n}: {\n autoUpdates: boolean\n datasetName: string\n defaults: {projectName: string}\n error: Output['error']\n git?: boolean | string\n mcpConfigured: EditorName[]\n noGit?: boolean\n organizationId: string | undefined\n output: Output\n outputPath: string\n overwriteFiles?: boolean\n packageManager?: string\n projectId: string\n remoteTemplateInfo: RepoInfo | undefined\n sluggedName: string\n template?: string\n templateToken?: string\n trace: TelemetryTrace<TelemetryUserProperties, InitStepResult>\n typescript?: boolean\n unattended: boolean\n workDir: string\n}): Promise<void> {\n const {\n template: resolvedTemplate,\n templateName,\n useTypeScript,\n } = await selectTemplate({\n remoteTemplateInfo,\n template,\n trace,\n typescript,\n unattended,\n })\n\n if (!remoteTemplateInfo && !resolvedTemplate) {\n error(`Template \"${templateName}\" not found`, {exit: 1})\n }\n\n await scaffoldAndInstall({\n autoUpdates,\n datasetName,\n defaults,\n displayName: '',\n git,\n noGit,\n organizationId,\n output,\n outputPath,\n overwriteFiles,\n packageManager,\n projectId,\n remoteTemplateInfo,\n sluggedName,\n templateName,\n templateToken,\n trace,\n unattended,\n useTypeScript,\n workDir,\n })\n\n const isCurrentDir = outputPath === process.cwd()\n const goToProjectDir = `\\n(${styleText('cyan', `cd ${outputPath}`)} to navigate to your new project directory)`\n\n //output for custom apps here\n output.log(\n `${logSymbols.success} ${styleText(['green', 'bold'], 'Success!')} Your custom app has been scaffolded.`,\n )\n if (!isCurrentDir) output.log(goToProjectDir)\n\n if (projectId && datasetName) {\n output.log(\n `\\nConfigured with project ${styleText('cyan', projectId)} and dataset ${styleText('cyan', datasetName)}.`,\n )\n output.log(\n 'Edit `src/App.tsx` to change these values or add more project / dataset pairs to your config.',\n )\n } else {\n output.log(\n `\\n${styleText('bold', 'Next')}, configure the project(s) and dataset(s) your app should work with in \\`src/App.tsx\\`.`,\n )\n }\n output.log('\\nRefer to our documentation for a walkthrough:')\n output.log(\n styleText(['blue', 'underline'], 'https://www.sanity.io/docs/app-sdk/sdk-configuration'),\n )\n if (mcpConfigured && mcpConfigured.length > 0) {\n const message = await getPostInitMCPPrompt(mcpConfigured)\n output.log(`\\n${message}`)\n output.log(`\\nLearn more: ${styleText('cyan', 'https://mcp.sanity.io')}`)\n output.log(\n `\\nHave feedback? Tell us in the community: ${styleText('cyan', 'https://www.sanity.io/community/join')}`,\n )\n }\n output.log('\\n')\n output.log(`Other helpful commands:`)\n output.log(`npx sanity docs browse to open the documentation in a browser`)\n output.log(`npx sanity dev to start the development server for your app`)\n output.log(`npx sanity deploy to deploy your app`)\n}\n"],"names":["styleText","logSymbols","getPostInitMCPPrompt","scaffoldAndInstall","selectTemplate","initApp","autoUpdates","datasetName","defaults","error","git","mcpConfigured","noGit","organizationId","output","outputPath","overwriteFiles","packageManager","projectId","remoteTemplateInfo","sluggedName","template","templateToken","trace","typescript","unattended","workDir","resolvedTemplate","templateName","useTypeScript","exit","displayName","isCurrentDir","process","cwd","goToProjectDir","log","success","length","message"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAGnC,SAAQC,UAAU,QAAO,sBAAqB;AAK9C,SAAQC,oBAAoB,QAAO,mBAAkB;AAErD,SAAQC,kBAAkB,EAAEC,cAAc,QAAO,wBAAuB;AAExE,OAAO,eAAeC,QAAQ,EAC5BC,WAAW,EACXC,WAAW,EACXC,QAAQ,EACRC,KAAK,EACLC,GAAG,EACHC,aAAa,EACbC,KAAK,EACLC,cAAc,EACdC,MAAM,EACNC,UAAU,EACVC,cAAc,EACdC,cAAc,EACdC,SAAS,EACTC,kBAAkB,EAClBC,WAAW,EACXC,QAAQ,EACRC,aAAa,EACbC,KAAK,EACLC,UAAU,EACVC,UAAU,EACVC,OAAO,EAuBR;IACC,MAAM,EACJL,UAAUM,gBAAgB,EAC1BC,YAAY,EACZC,aAAa,EACd,GAAG,MAAMzB,eAAe;QACvBe;QACAE;QACAE;QACAC;QACAC;IACF;IAEA,IAAI,CAACN,sBAAsB,CAACQ,kBAAkB;QAC5ClB,MAAM,CAAC,UAAU,EAAEmB,aAAa,WAAW,CAAC,EAAE;YAACE,MAAM;QAAC;IACxD;IAEA,MAAM3B,mBAAmB;QACvBG;QACAC;QACAC;QACAuB,aAAa;QACbrB;QACAE;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAQ;QACAN;QACAC;QACAE;QACAI;QACAH;IACF;IAEA,MAAMM,eAAejB,eAAekB,QAAQC,GAAG;IAC/C,MAAMC,iBAAiB,CAAC,GAAG,EAAEnC,UAAU,QAAQ,CAAC,GAAG,EAAEe,YAAY,EAAE,2CAA2C,CAAC;IAE/G,6BAA6B;IAC7BD,OAAOsB,GAAG,CACR,GAAGnC,WAAWoC,OAAO,CAAC,CAAC,EAAErC,UAAU;QAAC;QAAS;KAAO,EAAE,YAAY,qCAAqC,CAAC;IAE1G,IAAI,CAACgC,cAAclB,OAAOsB,GAAG,CAACD;IAE9B,IAAIjB,aAAaX,aAAa;QAC5BO,OAAOsB,GAAG,CACR,CAAC,0BAA0B,EAAEpC,UAAU,QAAQkB,WAAW,aAAa,EAAElB,UAAU,QAAQO,aAAa,CAAC,CAAC;QAE5GO,OAAOsB,GAAG,CACR;IAEJ,OAAO;QACLtB,OAAOsB,GAAG,CACR,CAAC,EAAE,EAAEpC,UAAU,QAAQ,QAAQ,uFAAuF,CAAC;IAE3H;IACAc,OAAOsB,GAAG,CAAC;IACXtB,OAAOsB,GAAG,CACRpC,UAAU;QAAC;QAAQ;KAAY,EAAE;IAEnC,IAAIW,iBAAiBA,cAAc2B,MAAM,GAAG,GAAG;QAC7C,MAAMC,UAAU,MAAMrC,qBAAqBS;QAC3CG,OAAOsB,GAAG,CAAC,CAAC,EAAE,EAAEG,SAAS;QACzBzB,OAAOsB,GAAG,CAAC,CAAC,cAAc,EAAEpC,UAAU,QAAQ,0BAA0B;QACxEc,OAAOsB,GAAG,CACR,CAAC,2CAA2C,EAAEpC,UAAU,QAAQ,yCAAyC;IAE7G;IACAc,OAAOsB,GAAG,CAAC;IACXtB,OAAOsB,GAAG,CAAC,CAAC,uBAAuB,CAAC;IACpCtB,OAAOsB,GAAG,CAAC,CAAC,iEAAiE,CAAC;IAC9EtB,OAAOsB,GAAG,CAAC,CAAC,uEAAuE,CAAC;IACpFtB,OAAOsB,GAAG,CAAC,CAAC,6CAA6C,CAAC;AAC5D"}
@@ -0,0 +1,37 @@
1
+ import { getSanityEnv } from '../../util/getSanityEnv.js';
2
+ import { createOrAppendEnvVars } from './env/createOrAppendEnvVars.js';
3
+ import { fetchPostInitPrompt } from './fetchPostInitPrompt.js';
4
+ /**
5
+ * Returns `true` when the user should be prompted for a flag value:
6
+ * i.e. we are NOT in unattended mode AND the flag was not explicitly provided.
7
+ */ export function shouldPrompt(unattended, flagValue) {
8
+ return !unattended && flagValue === undefined;
9
+ }
10
+ /**
11
+ * Returns the flag value if it is a boolean, otherwise returns the default.
12
+ */ export function flagOrDefault(flagValue, defaultValue) {
13
+ return typeof flagValue === 'boolean' ? flagValue : defaultValue;
14
+ }
15
+ export async function getPostInitMCPPrompt(editorsNames) {
16
+ return fetchPostInitPrompt(new Intl.ListFormat('en').format(editorsNames));
17
+ }
18
+ /**
19
+ * When running in a non-production Sanity environment (e.g. staging), write the
20
+ * `SANITY_INTERNAL_ENV` variable to a `.env` file in the output directory so that
21
+ * the bootstrapped project continues to target the same environment.
22
+ */ export async function writeStagingEnvIfNeeded(output, outputPath) {
23
+ const sanityEnv = getSanityEnv();
24
+ if (sanityEnv === 'production') return;
25
+ await createOrAppendEnvVars({
26
+ envVars: {
27
+ INTERNAL_ENV: sanityEnv
28
+ },
29
+ filename: '.env',
30
+ framework: null,
31
+ log: false,
32
+ output,
33
+ outputPath
34
+ });
35
+ }
36
+
37
+ //# sourceMappingURL=initHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/init/initHelpers.ts"],"sourcesContent":["import {type Output} from '@sanity/cli-core'\n\nimport {getSanityEnv} from '../../util/getSanityEnv.js'\nimport {type EditorName} from '../mcp/editorConfigs.js'\nimport {createOrAppendEnvVars} from './env/createOrAppendEnvVars.js'\nimport {fetchPostInitPrompt} from './fetchPostInitPrompt.js'\n\n/**\n * Returns `true` when the user should be prompted for a flag value:\n * i.e. we are NOT in unattended mode AND the flag was not explicitly provided.\n */\nexport function shouldPrompt(unattended: boolean, flagValue: unknown): boolean {\n return !unattended && flagValue === undefined\n}\n\n/**\n * Returns the flag value if it is a boolean, otherwise returns the default.\n */\nexport function flagOrDefault(flagValue: boolean | undefined, defaultValue: boolean): boolean {\n return typeof flagValue === 'boolean' ? flagValue : defaultValue\n}\n\nexport async function getPostInitMCPPrompt(editorsNames: EditorName[]): Promise<string> {\n return fetchPostInitPrompt(new Intl.ListFormat('en').format(editorsNames))\n}\n\n/**\n * When running in a non-production Sanity environment (e.g. staging), write the\n * `SANITY_INTERNAL_ENV` variable to a `.env` file in the output directory so that\n * the bootstrapped project continues to target the same environment.\n */\nexport async function writeStagingEnvIfNeeded(output: Output, outputPath: string): Promise<void> {\n const sanityEnv = getSanityEnv()\n if (sanityEnv === 'production') return\n\n await createOrAppendEnvVars({\n envVars: {INTERNAL_ENV: sanityEnv},\n filename: '.env',\n framework: null,\n log: false,\n output,\n outputPath,\n })\n}\n"],"names":["getSanityEnv","createOrAppendEnvVars","fetchPostInitPrompt","shouldPrompt","unattended","flagValue","undefined","flagOrDefault","defaultValue","getPostInitMCPPrompt","editorsNames","Intl","ListFormat","format","writeStagingEnvIfNeeded","output","outputPath","sanityEnv","envVars","INTERNAL_ENV","filename","framework","log"],"mappings":"AAEA,SAAQA,YAAY,QAAO,6BAA4B;AAEvD,SAAQC,qBAAqB,QAAO,iCAAgC;AACpE,SAAQC,mBAAmB,QAAO,2BAA0B;AAE5D;;;CAGC,GACD,OAAO,SAASC,aAAaC,UAAmB,EAAEC,SAAkB;IAClE,OAAO,CAACD,cAAcC,cAAcC;AACtC;AAEA;;CAEC,GACD,OAAO,SAASC,cAAcF,SAA8B,EAAEG,YAAqB;IACjF,OAAO,OAAOH,cAAc,YAAYA,YAAYG;AACtD;AAEA,OAAO,eAAeC,qBAAqBC,YAA0B;IACnE,OAAOR,oBAAoB,IAAIS,KAAKC,UAAU,CAAC,MAAMC,MAAM,CAACH;AAC9D;AAEA;;;;CAIC,GACD,OAAO,eAAeI,wBAAwBC,MAAc,EAAEC,UAAkB;IAC9E,MAAMC,YAAYjB;IAClB,IAAIiB,cAAc,cAAc;IAEhC,MAAMhB,sBAAsB;QAC1BiB,SAAS;YAACC,cAAcF;QAAS;QACjCG,UAAU;QACVC,WAAW;QACXC,KAAK;QACLP;QACAC;IACF;AACF"}
@@ -0,0 +1,246 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir, writeFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { styleText } from 'node:util';
5
+ import { subdebug } from '@sanity/cli-core';
6
+ import { confirm } from '@sanity/cli-core/ux';
7
+ import { execa } from 'execa';
8
+ import { promptForAppendEnv, promptForEmbeddedStudio, promptForNextTemplate, promptForStudioPath } from '../../prompts/init/nextjs.js';
9
+ import { promptForTypeScript } from '../../prompts/init/promptForTypescript.js';
10
+ import { createCorsOrigin, listCorsOrigins } from '../../services/cors.js';
11
+ import { getPeerDependencies } from '../../util/packageManager/getPeerDependencies.js';
12
+ import { installNewPackages } from '../../util/packageManager/installPackages.js';
13
+ import { getPartialEnvWithNpmPath } from '../../util/packageManager/packageManagerChoice.js';
14
+ import { countNestedFolders } from './countNestedFolders.js';
15
+ import { createOrAppendEnvVars } from './env/createOrAppendEnvVars.js';
16
+ import { flagOrDefault, getPostInitMCPPrompt, shouldPrompt, writeStagingEnvIfNeeded } from './initHelpers.js';
17
+ import { resolvePackageManager } from './resolvePackageManager.js';
18
+ import { sanityCliTemplate, sanityConfigTemplate, sanityFolder, sanityStudioTemplate } from './templates/nextjs/index.js';
19
+ const debug = subdebug('init');
20
+ async function writeOrOverwrite(filePath, content, workDir, params) {
21
+ if (existsSync(filePath)) {
22
+ let overwrite = flagOrDefault(params.overwriteFiles, false);
23
+ if (shouldPrompt(params.unattended, params.overwriteFiles)) {
24
+ overwrite = await confirm({
25
+ default: false,
26
+ message: `File ${styleText('yellow', filePath.replace(workDir, ''))} already exists. Do you want to overwrite it?`
27
+ });
28
+ }
29
+ if (!overwrite) {
30
+ return;
31
+ }
32
+ }
33
+ // make folder if not exists
34
+ const folderPath = path.dirname(filePath);
35
+ try {
36
+ await mkdir(folderPath, {
37
+ recursive: true
38
+ });
39
+ } catch {
40
+ debug('Error creating folder %s', folderPath);
41
+ }
42
+ await writeFile(filePath, content, {
43
+ encoding: 'utf8'
44
+ });
45
+ }
46
+ // write sanity folder files
47
+ async function writeSourceFiles({ fileExtension, files, folderPath, params, srcFolderPrefix, workDir }) {
48
+ for (const [filePath, content] of Object.entries(files)){
49
+ // check if file ends with full stop to indicate it's file and not directory (this only works with our template tree structure)
50
+ if (filePath.includes('.') && typeof content === 'string') {
51
+ await writeOrOverwrite(path.join(workDir, srcFolderPrefix ? 'src' : '', 'sanity', folderPath || '', `${filePath}${fileExtension}`), content, workDir, params);
52
+ } else {
53
+ await mkdir(path.join(workDir, srcFolderPrefix ? 'src' : '', 'sanity', filePath), {
54
+ recursive: true
55
+ });
56
+ if (typeof content === 'object') {
57
+ await writeSourceFiles({
58
+ fileExtension,
59
+ files: content,
60
+ folderPath: filePath,
61
+ params,
62
+ srcFolderPrefix,
63
+ workDir
64
+ });
65
+ }
66
+ }
67
+ }
68
+ }
69
+ export async function initNextJs({ datasetName, detectedFramework, envFilename, mcpConfigured, nextjsAppendEnv, nextjsEmbedStudio, output, overwriteFiles, packageManager, projectId, template, trace, typescript, unattended, workDir }) {
70
+ let useTypeScript = flagOrDefault(typescript, true);
71
+ if (shouldPrompt(unattended, typescript)) {
72
+ useTypeScript = await promptForTypeScript();
73
+ }
74
+ trace.log({
75
+ selectedOption: useTypeScript ? 'yes' : 'no',
76
+ step: 'useTypeScript'
77
+ });
78
+ const fileExtension = useTypeScript ? 'ts' : 'js';
79
+ let embeddedStudio = flagOrDefault(nextjsEmbedStudio, true);
80
+ if (shouldPrompt(unattended, nextjsEmbedStudio)) {
81
+ embeddedStudio = await promptForEmbeddedStudio();
82
+ }
83
+ let hasSrcFolder = false;
84
+ const writeParams = {
85
+ overwriteFiles,
86
+ unattended
87
+ };
88
+ if (embeddedStudio) {
89
+ // find source path (app or src/app)
90
+ const appDir = 'app';
91
+ let srcPath = path.join(workDir, appDir);
92
+ if (!existsSync(srcPath)) {
93
+ srcPath = path.join(workDir, 'src', appDir);
94
+ hasSrcFolder = true;
95
+ if (!existsSync(srcPath)) {
96
+ try {
97
+ await mkdir(srcPath, {
98
+ recursive: true
99
+ });
100
+ } catch {
101
+ debug('Error creating folder %s', srcPath);
102
+ }
103
+ }
104
+ }
105
+ const studioPath = unattended ? '/studio' : await promptForStudioPath();
106
+ const embeddedStudioRouteFilePath = path.join(srcPath, `${studioPath}/`, `[[...tool]]/page.${fileExtension}x`);
107
+ // this selects the correct template string based on whether the user is using the app or pages directory and
108
+ // replaces the ":configPath:" placeholder in the template with the correct path to the sanity.config.ts file.
109
+ // we account for the user-defined embeddedStudioPath (default /studio) is accounted for by creating enough "../"
110
+ // relative paths to reach the root level of the project
111
+ await writeOrOverwrite(embeddedStudioRouteFilePath, sanityStudioTemplate.replace(':configPath:', `${'../'.repeat(countNestedFolders(path.dirname(embeddedStudioRouteFilePath.slice(workDir.length))))}sanity.config`), workDir, writeParams);
112
+ const sanityConfigPath = path.join(workDir, `sanity.config.${fileExtension}`);
113
+ await writeOrOverwrite(sanityConfigPath, sanityConfigTemplate(hasSrcFolder).replace(':route:', embeddedStudioRouteFilePath.slice(workDir.length).replace('src/', '')).replace(':basePath:', studioPath), workDir, writeParams);
114
+ }
115
+ const sanityCliPath = path.join(workDir, `sanity.cli.${fileExtension}`);
116
+ await writeOrOverwrite(sanityCliPath, sanityCliTemplate, workDir, writeParams);
117
+ let templateToUse = template ?? 'clean';
118
+ if (shouldPrompt(unattended, template)) {
119
+ templateToUse = await promptForNextTemplate();
120
+ }
121
+ await writeSourceFiles({
122
+ fileExtension,
123
+ files: sanityFolder(useTypeScript, templateToUse),
124
+ folderPath: undefined,
125
+ params: writeParams,
126
+ srcFolderPrefix: hasSrcFolder,
127
+ workDir
128
+ });
129
+ let appendEnv = flagOrDefault(nextjsAppendEnv, true);
130
+ if (shouldPrompt(unattended, nextjsAppendEnv)) {
131
+ appendEnv = await promptForAppendEnv(envFilename);
132
+ }
133
+ if (appendEnv) {
134
+ await createOrAppendEnvVars({
135
+ envVars: {
136
+ DATASET: datasetName,
137
+ PROJECT_ID: projectId
138
+ },
139
+ filename: envFilename,
140
+ framework: detectedFramework,
141
+ log: true,
142
+ output,
143
+ outputPath: workDir
144
+ });
145
+ }
146
+ if (embeddedStudio) {
147
+ const nextjsLocalDevOrigin = 'http://localhost:3000';
148
+ const existingCorsOrigins = await listCorsOrigins(projectId);
149
+ const hasExistingCorsOrigin = existingCorsOrigins.some((item)=>item.origin === nextjsLocalDevOrigin);
150
+ if (!hasExistingCorsOrigin) {
151
+ try {
152
+ const createCorsRes = await createCorsOrigin({
153
+ allowCredentials: true,
154
+ origin: nextjsLocalDevOrigin,
155
+ projectId
156
+ });
157
+ output.log(createCorsRes.id ? `Added ${nextjsLocalDevOrigin} to CORS origins` : `Failed to add ${nextjsLocalDevOrigin} to CORS origins`);
158
+ } catch (corsError) {
159
+ debug(`Error creating new CORS Origin ${nextjsLocalDevOrigin}: ${corsError}`);
160
+ output.error(`Failed to add ${nextjsLocalDevOrigin} to CORS origins: ${corsError}`, {
161
+ exit: 1
162
+ });
163
+ }
164
+ }
165
+ }
166
+ const chosen = await resolvePackageManager({
167
+ interactive: !unattended,
168
+ output,
169
+ packageManager: packageManager,
170
+ targetDir: workDir
171
+ });
172
+ trace.log({
173
+ selectedOption: chosen,
174
+ step: 'selectPackageManager'
175
+ });
176
+ const packages = [
177
+ '@sanity/vision@5',
178
+ 'sanity@5',
179
+ '@sanity/image-url@2',
180
+ 'styled-components@6'
181
+ ];
182
+ if (templateToUse === 'blog') {
183
+ packages.push('@sanity/icons');
184
+ }
185
+ await installNewPackages({
186
+ packageManager: chosen,
187
+ packages
188
+ }, {
189
+ output,
190
+ workDir
191
+ });
192
+ // will refactor this later
193
+ const execOptions = {
194
+ cwd: workDir,
195
+ encoding: 'utf8',
196
+ env: getPartialEnvWithNpmPath(workDir),
197
+ stdio: 'inherit'
198
+ };
199
+ switch(chosen){
200
+ case 'npm':
201
+ {
202
+ await execa('npm', [
203
+ 'install',
204
+ 'next-sanity@12'
205
+ ], execOptions);
206
+ break;
207
+ }
208
+ case 'pnpm':
209
+ {
210
+ await execa('pnpm', [
211
+ 'install',
212
+ 'next-sanity@12'
213
+ ], execOptions);
214
+ break;
215
+ }
216
+ case 'yarn':
217
+ {
218
+ const peerDeps = await getPeerDependencies('next-sanity@12', workDir);
219
+ await installNewPackages({
220
+ packageManager: 'yarn',
221
+ packages: [
222
+ 'next-sanity@12',
223
+ ...peerDeps
224
+ ]
225
+ }, {
226
+ output,
227
+ workDir
228
+ });
229
+ break;
230
+ }
231
+ default:
232
+ {
233
+ break;
234
+ }
235
+ }
236
+ output.log(`\n${styleText('green', 'Success!')} Your Sanity configuration files has been added to this project`);
237
+ if (mcpConfigured && mcpConfigured.length > 0) {
238
+ const message = await getPostInitMCPPrompt(mcpConfigured);
239
+ output.log(`\n${message}`);
240
+ output.log(`\nLearn more: ${styleText('cyan', 'https://mcp.sanity.io')}`);
241
+ output.log(`\nHave feedback? Tell us in the community: ${styleText('cyan', 'https://www.sanity.io/community/join')}`);
242
+ }
243
+ await writeStagingEnvIfNeeded(output, workDir);
244
+ }
245
+
246
+ //# sourceMappingURL=initNextJs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/init/initNextJs.ts"],"sourcesContent":["import {existsSync} from 'node:fs'\nimport {mkdir, writeFile} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {type Output, subdebug, type TelemetryUserProperties} from '@sanity/cli-core'\nimport {confirm} from '@sanity/cli-core/ux'\nimport {type TelemetryTrace} from '@sanity/telemetry'\nimport {execa, type Options} from 'execa'\n\nimport {\n promptForAppendEnv,\n promptForEmbeddedStudio,\n promptForNextTemplate,\n promptForStudioPath,\n} from '../../prompts/init/nextjs.js'\nimport {promptForTypeScript} from '../../prompts/init/promptForTypescript.js'\nimport {createCorsOrigin, listCorsOrigins} from '../../services/cors.js'\nimport {type InitStepResult} from '../../telemetry/init.telemetry.js'\nimport {getPeerDependencies} from '../../util/packageManager/getPeerDependencies.js'\nimport {installNewPackages} from '../../util/packageManager/installPackages.js'\nimport {\n getPartialEnvWithNpmPath,\n type PackageManager,\n} from '../../util/packageManager/packageManagerChoice.js'\nimport {type EditorName} from '../mcp/editorConfigs.js'\nimport {countNestedFolders} from './countNestedFolders.js'\nimport {createOrAppendEnvVars} from './env/createOrAppendEnvVars.js'\nimport {\n flagOrDefault,\n getPostInitMCPPrompt,\n shouldPrompt,\n writeStagingEnvIfNeeded,\n} from './initHelpers.js'\nimport {resolvePackageManager} from './resolvePackageManager.js'\nimport {\n sanityCliTemplate,\n sanityConfigTemplate,\n sanityFolder,\n sanityStudioTemplate,\n} from './templates/nextjs/index.js'\nimport {type VersionedFramework} from './types.js'\n\nconst debug = subdebug('init')\n\nasync function writeOrOverwrite(\n filePath: string,\n content: string,\n workDir: string,\n params: {overwriteFiles?: boolean; unattended: boolean},\n) {\n if (existsSync(filePath)) {\n let overwrite = flagOrDefault(params.overwriteFiles, false)\n if (shouldPrompt(params.unattended, params.overwriteFiles)) {\n overwrite = await confirm({\n default: false,\n message: `File ${styleText(\n 'yellow',\n filePath.replace(workDir, ''),\n )} already exists. Do you want to overwrite it?`,\n })\n }\n\n if (!overwrite) {\n return\n }\n }\n\n // make folder if not exists\n const folderPath = path.dirname(filePath)\n\n try {\n await mkdir(folderPath, {recursive: true})\n } catch {\n debug('Error creating folder %s', folderPath)\n }\n\n await writeFile(filePath, content, {\n encoding: 'utf8',\n })\n}\n\n// write sanity folder files\nasync function writeSourceFiles({\n fileExtension,\n files,\n folderPath,\n params,\n srcFolderPrefix,\n workDir,\n}: {\n fileExtension: string\n files: Record<string, Record<string, string> | string>\n folderPath?: string\n params: {overwriteFiles?: boolean; unattended: boolean}\n srcFolderPrefix?: boolean\n workDir: string\n}) {\n for (const [filePath, content] of Object.entries(files)) {\n // check if file ends with full stop to indicate it's file and not directory (this only works with our template tree structure)\n if (filePath.includes('.') && typeof content === 'string') {\n await writeOrOverwrite(\n path.join(\n workDir,\n srcFolderPrefix ? 'src' : '',\n 'sanity',\n folderPath || '',\n `${filePath}${fileExtension}`,\n ),\n content,\n workDir,\n params,\n )\n } else {\n await mkdir(path.join(workDir, srcFolderPrefix ? 'src' : '', 'sanity', filePath), {\n recursive: true,\n })\n if (typeof content === 'object') {\n await writeSourceFiles({\n fileExtension,\n files: content,\n folderPath: filePath,\n params,\n srcFolderPrefix,\n workDir,\n })\n }\n }\n }\n}\n\nexport async function initNextJs({\n datasetName,\n detectedFramework,\n envFilename,\n mcpConfigured,\n nextjsAppendEnv,\n nextjsEmbedStudio,\n output,\n overwriteFiles,\n packageManager,\n projectId,\n template,\n trace,\n typescript,\n unattended,\n workDir,\n}: {\n datasetName: string\n detectedFramework: VersionedFramework | null\n envFilename: string\n mcpConfigured: EditorName[]\n nextjsAppendEnv?: boolean\n nextjsEmbedStudio?: boolean\n output: Output\n overwriteFiles?: boolean\n packageManager?: string\n projectId: string\n template?: string\n trace: TelemetryTrace<TelemetryUserProperties, InitStepResult>\n typescript?: boolean\n unattended: boolean\n workDir: string\n}): Promise<void> {\n let useTypeScript = flagOrDefault(typescript, true)\n if (shouldPrompt(unattended, typescript)) {\n useTypeScript = await promptForTypeScript()\n }\n trace.log({\n selectedOption: useTypeScript ? 'yes' : 'no',\n step: 'useTypeScript',\n })\n\n const fileExtension = useTypeScript ? 'ts' : 'js'\n let embeddedStudio = flagOrDefault(nextjsEmbedStudio, true)\n if (shouldPrompt(unattended, nextjsEmbedStudio)) {\n embeddedStudio = await promptForEmbeddedStudio()\n }\n let hasSrcFolder = false\n\n const writeParams = {overwriteFiles, unattended}\n\n if (embeddedStudio) {\n // find source path (app or src/app)\n const appDir = 'app'\n let srcPath = path.join(workDir, appDir)\n\n if (!existsSync(srcPath)) {\n srcPath = path.join(workDir, 'src', appDir)\n hasSrcFolder = true\n if (!existsSync(srcPath)) {\n try {\n await mkdir(srcPath, {recursive: true})\n } catch {\n debug('Error creating folder %s', srcPath)\n }\n }\n }\n\n const studioPath = unattended ? '/studio' : await promptForStudioPath()\n\n const embeddedStudioRouteFilePath = path.join(\n srcPath,\n `${studioPath}/`,\n `[[...tool]]/page.${fileExtension}x`,\n )\n\n // this selects the correct template string based on whether the user is using the app or pages directory and\n // replaces the \":configPath:\" placeholder in the template with the correct path to the sanity.config.ts file.\n // we account for the user-defined embeddedStudioPath (default /studio) is accounted for by creating enough \"../\"\n // relative paths to reach the root level of the project\n await writeOrOverwrite(\n embeddedStudioRouteFilePath,\n sanityStudioTemplate.replace(\n ':configPath:',\n `${'../'.repeat(countNestedFolders(path.dirname(embeddedStudioRouteFilePath.slice(workDir.length))))}sanity.config`,\n ),\n workDir,\n writeParams,\n )\n\n const sanityConfigPath = path.join(workDir, `sanity.config.${fileExtension}`)\n await writeOrOverwrite(\n sanityConfigPath,\n sanityConfigTemplate(hasSrcFolder)\n .replace(':route:', embeddedStudioRouteFilePath.slice(workDir.length).replace('src/', ''))\n .replace(':basePath:', studioPath),\n workDir,\n writeParams,\n )\n }\n\n const sanityCliPath = path.join(workDir, `sanity.cli.${fileExtension}`)\n await writeOrOverwrite(sanityCliPath, sanityCliTemplate, workDir, writeParams)\n\n let templateToUse = template ?? 'clean'\n if (shouldPrompt(unattended, template)) {\n templateToUse = await promptForNextTemplate()\n }\n\n await writeSourceFiles({\n fileExtension,\n files: sanityFolder(useTypeScript, templateToUse as 'blog' | 'clean'),\n folderPath: undefined,\n params: writeParams,\n srcFolderPrefix: hasSrcFolder,\n workDir,\n })\n\n let appendEnv = flagOrDefault(nextjsAppendEnv, true)\n if (shouldPrompt(unattended, nextjsAppendEnv)) {\n appendEnv = await promptForAppendEnv(envFilename)\n }\n\n if (appendEnv) {\n await createOrAppendEnvVars({\n envVars: {\n DATASET: datasetName,\n PROJECT_ID: projectId,\n },\n filename: envFilename,\n framework: detectedFramework,\n log: true,\n output,\n outputPath: workDir,\n })\n }\n\n if (embeddedStudio) {\n const nextjsLocalDevOrigin = 'http://localhost:3000'\n const existingCorsOrigins = await listCorsOrigins(projectId)\n const hasExistingCorsOrigin = existingCorsOrigins.some(\n (item: {origin: string}) => item.origin === nextjsLocalDevOrigin,\n )\n if (!hasExistingCorsOrigin) {\n try {\n const createCorsRes = await createCorsOrigin({\n allowCredentials: true,\n origin: nextjsLocalDevOrigin,\n projectId,\n })\n\n output.log(\n createCorsRes.id\n ? `Added ${nextjsLocalDevOrigin} to CORS origins`\n : `Failed to add ${nextjsLocalDevOrigin} to CORS origins`,\n )\n } catch (corsError) {\n debug(`Error creating new CORS Origin ${nextjsLocalDevOrigin}: ${corsError}`)\n output.error(`Failed to add ${nextjsLocalDevOrigin} to CORS origins: ${corsError}`, {\n exit: 1,\n })\n }\n }\n }\n\n const chosen = await resolvePackageManager({\n interactive: !unattended,\n output,\n packageManager: packageManager as PackageManager,\n targetDir: workDir,\n })\n trace.log({selectedOption: chosen, step: 'selectPackageManager'})\n const packages = ['@sanity/vision@5', 'sanity@5', '@sanity/image-url@2', 'styled-components@6']\n if (templateToUse === 'blog') {\n packages.push('@sanity/icons')\n }\n await installNewPackages(\n {\n packageManager: chosen,\n packages,\n },\n {\n output,\n workDir,\n },\n )\n\n // will refactor this later\n const execOptions: Options = {\n cwd: workDir,\n encoding: 'utf8',\n env: getPartialEnvWithNpmPath(workDir),\n stdio: 'inherit',\n }\n\n switch (chosen) {\n case 'npm': {\n await execa('npm', ['install', 'next-sanity@12'], execOptions)\n break\n }\n case 'pnpm': {\n await execa('pnpm', ['install', 'next-sanity@12'], execOptions)\n break\n }\n case 'yarn': {\n const peerDeps = await getPeerDependencies('next-sanity@12', workDir)\n await installNewPackages(\n {packageManager: 'yarn', packages: ['next-sanity@12', ...peerDeps]},\n {output, workDir},\n )\n break\n }\n default: {\n // bun and manual - do nothing or handle differently\n break\n }\n }\n\n output.log(\n `\\n${styleText('green', 'Success!')} Your Sanity configuration files has been added to this project`,\n )\n if (mcpConfigured && mcpConfigured.length > 0) {\n const message = await getPostInitMCPPrompt(mcpConfigured)\n output.log(`\\n${message}`)\n output.log(`\\nLearn more: ${styleText('cyan', 'https://mcp.sanity.io')}`)\n output.log(\n `\\nHave feedback? Tell us in the community: ${styleText('cyan', 'https://www.sanity.io/community/join')}`,\n )\n }\n\n await writeStagingEnvIfNeeded(output, workDir)\n}\n"],"names":["existsSync","mkdir","writeFile","path","styleText","subdebug","confirm","execa","promptForAppendEnv","promptForEmbeddedStudio","promptForNextTemplate","promptForStudioPath","promptForTypeScript","createCorsOrigin","listCorsOrigins","getPeerDependencies","installNewPackages","getPartialEnvWithNpmPath","countNestedFolders","createOrAppendEnvVars","flagOrDefault","getPostInitMCPPrompt","shouldPrompt","writeStagingEnvIfNeeded","resolvePackageManager","sanityCliTemplate","sanityConfigTemplate","sanityFolder","sanityStudioTemplate","debug","writeOrOverwrite","filePath","content","workDir","params","overwrite","overwriteFiles","unattended","default","message","replace","folderPath","dirname","recursive","encoding","writeSourceFiles","fileExtension","files","srcFolderPrefix","Object","entries","includes","join","initNextJs","datasetName","detectedFramework","envFilename","mcpConfigured","nextjsAppendEnv","nextjsEmbedStudio","output","packageManager","projectId","template","trace","typescript","useTypeScript","log","selectedOption","step","embeddedStudio","hasSrcFolder","writeParams","appDir","srcPath","studioPath","embeddedStudioRouteFilePath","repeat","slice","length","sanityConfigPath","sanityCliPath","templateToUse","undefined","appendEnv","envVars","DATASET","PROJECT_ID","filename","framework","outputPath","nextjsLocalDevOrigin","existingCorsOrigins","hasExistingCorsOrigin","some","item","origin","createCorsRes","allowCredentials","id","corsError","error","exit","chosen","interactive","targetDir","packages","push","execOptions","cwd","env","stdio","peerDeps"],"mappings":"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"}