@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.
- package/README.md +16 -10
- package/dist/actions/init/bootstrapLocalTemplate.js +16 -1
- package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
- package/dist/actions/init/initApp.js +72 -0
- package/dist/actions/init/initApp.js.map +1 -0
- package/dist/actions/init/initHelpers.js +37 -0
- package/dist/actions/init/initHelpers.js.map +1 -0
- package/dist/actions/init/initNextJs.js +246 -0
- package/dist/actions/init/initNextJs.js.map +1 -0
- package/dist/actions/init/initStudio.js +127 -0
- package/dist/actions/init/initStudio.js.map +1 -0
- package/dist/actions/init/scaffoldTemplate.js +114 -0
- package/dist/actions/init/scaffoldTemplate.js.map +1 -0
- package/dist/actions/init/templates/appQuickstart.js +2 -1
- package/dist/actions/init/templates/appQuickstart.js.map +1 -1
- package/dist/actions/init/templates/appSanityUi.js +2 -1
- package/dist/actions/init/templates/appSanityUi.js.map +1 -1
- package/dist/actions/init/templates/shopify.js +6 -6
- package/dist/actions/init/templates/shopify.js.map +1 -1
- package/dist/actions/init/templates/shopifyOnline.js +2 -2
- package/dist/actions/init/templates/shopifyOnline.js.map +1 -1
- package/dist/actions/mcp/detectAvailableEditors.js +16 -3
- package/dist/actions/mcp/detectAvailableEditors.js.map +1 -1
- package/dist/actions/mcp/editorConfigs.js +192 -132
- package/dist/actions/mcp/editorConfigs.js.map +1 -1
- package/dist/actions/mcp/setupMCP.js +4 -1
- package/dist/actions/mcp/setupMCP.js.map +1 -1
- package/dist/actions/mcp/writeMCPConfig.js +2 -2
- package/dist/actions/mcp/writeMCPConfig.js.map +1 -1
- package/dist/actions/schema/extractSchema.js +5 -7
- package/dist/actions/schema/extractSchema.js.map +1 -1
- package/dist/commands/datasets/copy.js +14 -0
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/commands/init.js +149 -482
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp/configure.js +1 -1
- package/dist/commands/mcp/configure.js.map +1 -1
- package/dist/hooks/prerun/injectEnvVariables.js +3 -5
- package/dist/hooks/prerun/injectEnvVariables.js.map +1 -1
- package/dist/services/datasets.js +2 -1
- package/dist/services/datasets.js.map +1 -1
- package/dist/telemetry/init.telemetry.js.map +1 -1
- package/dist/util/packageManager/installationInfo/detectPackages.js +13 -7
- package/dist/util/packageManager/installationInfo/detectPackages.js.map +1 -1
- package/dist/util/update/fetchUpdateInfo.js +40 -0
- package/dist/util/update/fetchUpdateInfo.js.map +1 -0
- package/dist/util/update/fetchUpdateInfo.worker.js +19 -0
- package/dist/util/update/fetchUpdateInfo.worker.js.map +1 -0
- package/dist/util/update/getRunnerUpdateCommand.js +33 -0
- package/dist/util/update/getRunnerUpdateCommand.js.map +1 -0
- package/dist/util/update/getUpdateCommand.js +6 -7
- package/dist/util/update/getUpdateCommand.js.map +1 -1
- package/dist/util/update/packageRunner.js +10 -0
- package/dist/util/update/packageRunner.js.map +1 -0
- package/dist/util/update/resolveRunnerPackage.js +45 -0
- package/dist/util/update/resolveRunnerPackage.js.map +1 -0
- package/dist/util/update/resolveUpdateTarget.js +31 -0
- package/dist/util/update/resolveUpdateTarget.js.map +1 -0
- package/dist/util/update/showNotificationUpdate.js +8 -6
- package/dist/util/update/showNotificationUpdate.js.map +1 -1
- package/dist/util/update/updateChecker.js +73 -38
- package/dist/util/update/updateChecker.js.map +1 -1
- package/oclif.manifest.json +540 -525
- package/package.json +6 -6
- package/templates/app-quickstart/src/App.tsx +2 -2
- package/templates/app-sanity-ui/src/App.tsx +2 -2
- package/templates/shopify/schemaTypes/objects/hotspot/imageWithProductHotspotsType.ts +1 -1
- package/dist/util/update/fetchLatestVersion.js +0 -21
- 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>] [--
|
|
911
|
-
[--
|
|
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>
|
|
919
|
-
--detach
|
|
920
|
-
--limit=<value>
|
|
921
|
-
--list
|
|
922
|
-
--offset=<value>
|
|
923
|
-
--skip-
|
|
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,
|
|
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
|
-
|
|
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":"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"}
|
|
@@ -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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"}
|