@sanity/cli 3.93.1-next.9.198ab74452 → 3.94.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 (149) hide show
  1. package/lib/_chunks-cjs/cli.js +1 -1
  2. package/lib/_chunks-cjs/cli.js.map +1 -1
  3. package/package.json +10 -11
  4. package/templates/blog/README.md +1 -1
  5. package/templates/clean/README.md +1 -1
  6. package/templates/ecommerce/README.md +1 -1
  7. package/templates/get-started/README.md +1 -1
  8. package/templates/moviedb/README.md +1 -1
  9. package/templates/quickstart/README.md +1 -1
  10. package/src/CommandRunner.ts +0 -219
  11. package/src/__telemetry__/cli.telemetry.ts +0 -29
  12. package/src/__telemetry__/init.telemetry.ts +0 -95
  13. package/src/actions/codemod/codemodAction.ts +0 -109
  14. package/src/actions/codemod/mods/deskRename.ts +0 -19
  15. package/src/actions/codemod/mods/index.ts +0 -9
  16. package/src/actions/codemod/mods/partsTypeDirective.ts +0 -28
  17. package/src/actions/codemod/mods/reactIconsV3.ts +0 -54
  18. package/src/actions/codemod/types.ts +0 -10
  19. package/src/actions/init-plugin/bootstrapFromTemplate.ts +0 -196
  20. package/src/actions/init-project/bootstrapLocalTemplate.ts +0 -201
  21. package/src/actions/init-project/bootstrapRemoteTemplate.ts +0 -118
  22. package/src/actions/init-project/createAppCliConfig.ts +0 -24
  23. package/src/actions/init-project/createCliConfig.ts +0 -31
  24. package/src/actions/init-project/createPackageManifest.ts +0 -102
  25. package/src/actions/init-project/createStudioConfig.ts +0 -53
  26. package/src/actions/init-project/determineAppTemplate.ts +0 -13
  27. package/src/actions/init-project/fsUtils.ts +0 -40
  28. package/src/actions/init-project/git.ts +0 -59
  29. package/src/actions/init-project/initProject.ts +0 -1708
  30. package/src/actions/init-project/processTemplate.ts +0 -55
  31. package/src/actions/init-project/promptForDatasetName.ts +0 -68
  32. package/src/actions/init-project/prompts/index.ts +0 -51
  33. package/src/actions/init-project/prompts/nextjs.ts +0 -59
  34. package/src/actions/init-project/readPackageJson.ts +0 -17
  35. package/src/actions/init-project/templates/appQuickstart.ts +0 -23
  36. package/src/actions/init-project/templates/appSanityUi.ts +0 -25
  37. package/src/actions/init-project/templates/blog.ts +0 -5
  38. package/src/actions/init-project/templates/clean.ts +0 -5
  39. package/src/actions/init-project/templates/getStarted.ts +0 -37
  40. package/src/actions/init-project/templates/index.ts +0 -24
  41. package/src/actions/init-project/templates/moviedb.ts +0 -35
  42. package/src/actions/init-project/templates/nextjs/index.ts +0 -238
  43. package/src/actions/init-project/templates/nextjs/schemaTypes/blog.ts +0 -252
  44. package/src/actions/init-project/templates/quickstart.ts +0 -5
  45. package/src/actions/init-project/templates/shopify.ts +0 -78
  46. package/src/actions/init-project/templates/shopifyOnline.ts +0 -50
  47. package/src/actions/init-project/updateInitialTemplateMetadata.ts +0 -24
  48. package/src/actions/login/login.telemetry.ts +0 -18
  49. package/src/actions/login/login.ts +0 -350
  50. package/src/actions/login/types.ts +0 -19
  51. package/src/actions/project/createProject.ts +0 -36
  52. package/src/actions/telemetry/setTelemetryConsent.ts +0 -101
  53. package/src/actions/typegen/generate.telemetry.ts +0 -20
  54. package/src/actions/typegen/generateAction.ts +0 -210
  55. package/src/actions/versions/findSanityModuleVersions.ts +0 -185
  56. package/src/actions/yarn/events.ts +0 -73
  57. package/src/cli.ts +0 -350
  58. package/src/cliClient.ts +0 -62
  59. package/src/commands/blueprints/addBlueprintsCommand.ts +0 -155
  60. package/src/commands/blueprints/blueprintsGroup.ts +0 -10
  61. package/src/commands/blueprints/configBlueprintsCommand.ts +0 -86
  62. package/src/commands/blueprints/deployBlueprintsCommand.ts +0 -63
  63. package/src/commands/blueprints/destroyBlueprintsCommand.ts +0 -78
  64. package/src/commands/blueprints/infoBlueprintsCommand.ts +0 -55
  65. package/src/commands/blueprints/initBlueprintsCommand.ts +0 -99
  66. package/src/commands/blueprints/logsBlueprintsCommand.ts +0 -66
  67. package/src/commands/blueprints/planBlueprintsCommand.ts +0 -51
  68. package/src/commands/blueprints/stacksBlueprintsCommand.ts +0 -66
  69. package/src/commands/codemod/codemodCommand.ts +0 -32
  70. package/src/commands/debug/debugCommand.ts +0 -26
  71. package/src/commands/debug/printDebugInfo.ts +0 -243
  72. package/src/commands/docs/docsCommand.ts +0 -20
  73. package/src/commands/functions/devFunctionsCommand.ts +0 -73
  74. package/src/commands/functions/envFunctionsCommand.ts +0 -105
  75. package/src/commands/functions/functionsGroup.ts +0 -10
  76. package/src/commands/functions/logsFunctionsCommand.ts +0 -94
  77. package/src/commands/functions/testFunctionsCommand.ts +0 -93
  78. package/src/commands/help/helpCommand.ts +0 -21
  79. package/src/commands/help/showHelp.ts +0 -58
  80. package/src/commands/index.ts +0 -72
  81. package/src/commands/init/initCommand.ts +0 -123
  82. package/src/commands/install/installCommand.ts +0 -38
  83. package/src/commands/learn/learnCommand.ts +0 -20
  84. package/src/commands/login/loginCommand.ts +0 -29
  85. package/src/commands/logout/logoutCommand.ts +0 -52
  86. package/src/commands/manage/manageCommand.ts +0 -24
  87. package/src/commands/projects/listProjectsCommand.ts +0 -62
  88. package/src/commands/projects/projectsGroup.ts +0 -10
  89. package/src/commands/telemetry/disableTelemetryCommand.ts +0 -19
  90. package/src/commands/telemetry/enableTelemetryCommand.ts +0 -19
  91. package/src/commands/telemetry/telemetryGroup.ts +0 -10
  92. package/src/commands/telemetry/telemetryStatusCommand.ts +0 -89
  93. package/src/commands/typegen/generateTypesCommand.ts +0 -56
  94. package/src/commands/typegen/typegenGroup.ts +0 -10
  95. package/src/commands/versions/printVersionResult.ts +0 -51
  96. package/src/commands/versions/versionsCommand.ts +0 -13
  97. package/src/config.ts +0 -14
  98. package/src/debug.ts +0 -3
  99. package/src/index.ts +0 -6
  100. package/src/outputters/cliOutputter.ts +0 -47
  101. package/src/packageManager/getInstallCommand.ts +0 -26
  102. package/src/packageManager/getUpgradeCommand.ts +0 -52
  103. package/src/packageManager/index.ts +0 -33
  104. package/src/packageManager/installPackages.ts +0 -99
  105. package/src/packageManager/packageManagerChoice.ts +0 -204
  106. package/src/packageManager/uninstallPackages.ts +0 -44
  107. package/src/packageManager/yarnStub.ts +0 -22
  108. package/src/prompters/cliPrompter.ts +0 -9
  109. package/src/run.ts +0 -8
  110. package/src/studioDependencies.ts +0 -25
  111. package/src/types.ts +0 -387
  112. package/src/util/canLaunchBrowser.ts +0 -12
  113. package/src/util/cliWorker.ts +0 -34
  114. package/src/util/clientWrapper.ts +0 -119
  115. package/src/util/copy.ts +0 -50
  116. package/src/util/createExpiringConfig.ts +0 -80
  117. package/src/util/createTelemetryStore.ts +0 -204
  118. package/src/util/detectRuntime.ts +0 -12
  119. package/src/util/dynamicRequire.ts +0 -17
  120. package/src/util/frameworkPort.ts +0 -63
  121. package/src/util/generateCommandsDocumentation.ts +0 -62
  122. package/src/util/getCliConfig.ts +0 -172
  123. package/src/util/getCliVersion.ts +0 -22
  124. package/src/util/getLocalVersion.ts +0 -35
  125. package/src/util/getProjectDefaults.ts +0 -103
  126. package/src/util/getProviderName.ts +0 -9
  127. package/src/util/getUserConfig.ts +0 -15
  128. package/src/util/isCi.ts +0 -7
  129. package/src/util/isCommandGroup.ts +0 -7
  130. package/src/util/isInteractive.ts +0 -3
  131. package/src/util/isTrueish.ts +0 -8
  132. package/src/util/journeyConfig.ts +0 -280
  133. package/src/util/loadEnv.ts +0 -110
  134. package/src/util/mergeCommands.ts +0 -78
  135. package/src/util/neatStack.ts +0 -30
  136. package/src/util/noSuchCommandText.ts +0 -91
  137. package/src/util/parseArguments.ts +0 -76
  138. package/src/util/pathExists.ts +0 -14
  139. package/src/util/readJson.ts +0 -6
  140. package/src/util/readdirRecursive.ts +0 -26
  141. package/src/util/remoteTemplate.ts +0 -320
  142. package/src/util/resolveLatestVersions.ts +0 -24
  143. package/src/util/resolveRootDir.ts +0 -59
  144. package/src/util/telemetryDisclosure.ts +0 -45
  145. package/src/util/updateNotifier.ts +0 -158
  146. package/src/util/writeJson.ts +0 -6
  147. package/src/workers/getAndWriteJourneySchema.ts +0 -7
  148. package/src/workers/getCliConfig.ts +0 -14
  149. package/src/workers/typegenGenerate.ts +0 -228
@@ -1,10 +0,0 @@
1
- import {type CliCommandContext} from '../../types'
2
-
3
- export interface CodeMod {
4
- purpose: string
5
- description: string
6
- verify?: (context: CliCommandContext) => Promise<void>
7
-
8
- // Must match filename in `cli/codemods/`
9
- filename: string
10
- }
@@ -1,196 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import path from 'node:path'
3
-
4
- import {absolutify, pathIsEmpty} from '@sanity/util/fs'
5
- import decompress from 'decompress'
6
- import {getIt} from 'get-it'
7
- import {promise} from 'get-it/middleware'
8
- import resolveFrom from 'resolve-from'
9
- import semver from 'semver'
10
- import validateNpmPackageName from 'validate-npm-package-name'
11
-
12
- import {type CliCommandContext} from '../..'
13
- import {debug} from '../../debug'
14
- import {type SanityJson} from '../../types'
15
- import {dynamicRequire} from '../../util/dynamicRequire'
16
- import {getCliVersion} from '../../util/getCliVersion'
17
- import {readJson} from '../../util/readJson'
18
-
19
- const request = getIt([promise()])
20
-
21
- interface TemplateManifest {
22
- sanityTemplate: {
23
- minimumBaseVersion?: string
24
- minimumCliVersion?: string
25
- suggestedName?: string
26
- requiresConfig?: boolean
27
- dependencies?: Record<string, string>
28
- }
29
- }
30
-
31
- export async function bootstrapFromTemplate(
32
- context: CliCommandContext,
33
- url: string,
34
- ): Promise<{
35
- name: string
36
- outputPath: string
37
- inPluginsPath: boolean
38
- dependencies: any
39
- }> {
40
- const {prompt, workDir} = context
41
- const cliVersion = await getCliVersion()
42
- let inProjectContext = false
43
- try {
44
- const projectManifest = await readJson<SanityJson>(path.join(workDir, 'sanity.json'))
45
- inProjectContext = Boolean(projectManifest.root)
46
- } catch {
47
- // Intentional noop
48
- }
49
-
50
- debug(inProjectContext ? 'Project context found' : 'Not in project context')
51
-
52
- let zip: decompress.File[]
53
- try {
54
- debug('Fetching zip from %s', url)
55
- zip = await getZip(url)
56
- debug('Zip finished downloading')
57
- } catch (err) {
58
- err.message = `Failed to get template: ${err.message}`
59
- throw err
60
- }
61
-
62
- debug('Looking up template manifest from zip')
63
- const manifest = zip.find(
64
- (file) => path.basename(file.path) === 'package.json' && !file.path.includes('node_modules'),
65
- )
66
-
67
- if (!manifest) {
68
- throw new Error('Could not find `package.json` in template')
69
- }
70
-
71
- // Note: Paths inside the zips are always unix-style, so do not use `path.join` here
72
- const baseDir = `${path.dirname(manifest.path)}/template`
73
- debug('Manifest path resolved to %s', manifest.path)
74
- debug('Base directory resolved to %s', baseDir)
75
-
76
- const templateFiles = zip.filter(
77
- (file) => file.type === 'file' && file.path.indexOf(baseDir) === 0,
78
- )
79
- debug('%d files found in template', templateFiles.length)
80
-
81
- const manifestContent = parseJson<TemplateManifest>(manifest.data.toString())
82
- const tplVars = manifestContent?.sanityTemplate || {}
83
- const {minimumBaseVersion, minimumCliVersion} = tplVars
84
-
85
- if (minimumBaseVersion) {
86
- debug('Template requires Sanity version %s', minimumBaseVersion)
87
- const installed = getSanityVersion(workDir, cliVersion)
88
- debug('Installed Sanity version is %s', installed)
89
-
90
- if (semver.lt(installed, minimumBaseVersion)) {
91
- throw new Error(
92
- `Template requires Sanity at version ${minimumBaseVersion}, installed is ${installed}`,
93
- )
94
- }
95
- }
96
-
97
- if (minimumCliVersion) {
98
- debug('Template requires Sanity CLI version %s', minimumCliVersion)
99
- debug('Installed CLI version is %s', cliVersion)
100
-
101
- if (semver.lt(cliVersion, minimumCliVersion)) {
102
- throw new Error(
103
- `Template requires @sanity/cli at version ${minimumCliVersion}, installed is ${cliVersion}`,
104
- )
105
- }
106
- }
107
-
108
- const name = await prompt.single({
109
- type: 'input',
110
- message: 'Plugin name:',
111
- default: tplVars.suggestedName || '',
112
- validate: async (pkgName) => {
113
- const {validForNewPackages} = validateNpmPackageName(pkgName)
114
- if (!validForNewPackages) {
115
- return 'Name must be a valid npm package name (https://docs.npmjs.com/files/package.json#name)'
116
- }
117
-
118
- const outputPath = path.join(workDir, 'plugins', pkgName)
119
- const isEmpty = await pathIsEmpty(outputPath)
120
- if (inProjectContext && !isEmpty) {
121
- return 'Plugin with given name already exists in project'
122
- }
123
-
124
- return true
125
- },
126
- })
127
-
128
- let outputPath = path.join(workDir, 'plugins', name)
129
- if (!inProjectContext) {
130
- const cwdIsEmpty = await pathIsEmpty(workDir)
131
- outputPath = await prompt.single({
132
- type: 'input',
133
- message: 'Output path:',
134
- default: cwdIsEmpty ? workDir : path.join(workDir, name),
135
- validate: validateEmptyPath,
136
- filter: absolutify,
137
- })
138
- }
139
-
140
- debug('Output path set to %s', outputPath)
141
-
142
- let createConfig = tplVars.requiresConfig
143
- if (typeof createConfig === 'undefined') {
144
- createConfig = await prompt.single({
145
- type: 'confirm',
146
- message: 'Does the plugin need a configuration file?',
147
- default: false,
148
- })
149
- }
150
-
151
- debug('Ensuring directory exists: %s', outputPath)
152
- await fs.mkdir(outputPath, {recursive: true})
153
-
154
- await Promise.all(
155
- templateFiles.map((file: {path: string; data: string | Buffer}) => {
156
- const filename = file.path.slice(baseDir.length)
157
-
158
- debug('Writing template file "%s" to "%s"', filename, outputPath)
159
- return fs.writeFile(path.join(outputPath, filename), file.data)
160
- }),
161
- )
162
-
163
- return {name, outputPath, inPluginsPath: inProjectContext, dependencies: tplVars.dependencies}
164
- }
165
-
166
- async function validateEmptyPath(dir: string) {
167
- const isEmpty = await pathIsEmpty(dir)
168
- return isEmpty ? true : 'Path is not empty'
169
- }
170
-
171
- function getZip(url: string): Promise<decompress.File[]> {
172
- return request({url, rawBody: true}).then(
173
- (res: {statusCode: number; statusMessage: string; body: Buffer}) => {
174
- if (res.statusCode > 299) {
175
- const httpErr = ['HTTP', res.statusCode, res.statusMessage].filter(Boolean).join(' ')
176
- throw new Error(`${httpErr} trying to download ${url}`)
177
- }
178
-
179
- return decompress(res.body)
180
- },
181
- )
182
- }
183
-
184
- function parseJson<T = any>(json: string): T | undefined {
185
- try {
186
- return JSON.parse(json)
187
- } catch {
188
- return undefined
189
- }
190
- }
191
-
192
- function getSanityVersion(workDir: string, fallback: string): string {
193
- // This is only used in v2, thus `@sanity/base`
194
- const basePkg = resolveFrom.silent(workDir, '@sanity/base/package.json')
195
- return basePkg ? dynamicRequire(basePkg).version : fallback
196
- }
@@ -1,201 +0,0 @@
1
- import fs from 'node:fs/promises'
2
- import path from 'node:path'
3
-
4
- import chalk from 'chalk'
5
- import {deburr} from 'lodash'
6
-
7
- import {debug} from '../../debug'
8
- import {studioDependencies} from '../../studioDependencies'
9
- import {type CliCommandContext} from '../../types'
10
- import {copy} from '../../util/copy'
11
- import {getAndWriteJourneySchemaWorker} from '../../util/journeyConfig'
12
- import {resolveLatestVersions} from '../../util/resolveLatestVersions'
13
- import {createAppCliConfig} from './createAppCliConfig'
14
- import {createCliConfig} from './createCliConfig'
15
- import {createPackageManifest} from './createPackageManifest'
16
- import {createStudioConfig, type GenerateConfigOptions} from './createStudioConfig'
17
- import {determineAppTemplate} from './determineAppTemplate'
18
- import {type ProjectTemplate} from './initProject'
19
- import templates from './templates'
20
- import {updateInitialTemplateMetadata} from './updateInitialTemplateMetadata'
21
-
22
- export interface BootstrapLocalOptions {
23
- packageName: string
24
- templateName: string
25
- /**
26
- * Used for initializing a project from a server schema that is saved in the Journey API
27
- * @beta
28
- */
29
- schemaUrl?: string
30
- outputPath: string
31
- useTypeScript: boolean
32
- variables: GenerateConfigOptions['variables']
33
- }
34
-
35
- export async function bootstrapLocalTemplate(
36
- opts: BootstrapLocalOptions,
37
- context: CliCommandContext,
38
- ): Promise<ProjectTemplate> {
39
- const {apiClient, cliRoot, output} = context
40
- const templatesDir = path.join(cliRoot, 'templates')
41
- const {outputPath, templateName, useTypeScript, packageName, variables} = opts
42
- const sourceDir = path.join(templatesDir, templateName)
43
- const sharedDir = path.join(templatesDir, 'shared')
44
- const isAppTemplate = determineAppTemplate(templateName)
45
-
46
- // Check that we have a template info file (dependencies, plugins etc)
47
- const template = templates[templateName]
48
- if (!template) {
49
- throw new Error(`Template "${templateName}" not defined`)
50
- }
51
-
52
- // Copy template files
53
- debug('Copying files from template "%s" to "%s"', templateName, outputPath)
54
- let spinner = output
55
- .spinner(
56
- opts.schemaUrl ? 'Extracting your Sanity configuration' : 'Bootstrapping files from template',
57
- )
58
- .start()
59
-
60
- await copy(sourceDir, outputPath, {
61
- rename: useTypeScript ? toTypeScriptPath : undefined,
62
- })
63
- await copy(path.join(sharedDir, 'gitignore.txt'), outputPath, {rename: () => '.gitignore'})
64
-
65
- if (useTypeScript) {
66
- await fs.copyFile(path.join(sharedDir, 'tsconfig.json'), path.join(outputPath, 'tsconfig.json'))
67
- }
68
-
69
- // If we have a schemaUrl, get the schema and write it to disk
70
- // At this point the selected template should already have been forced to "clean"
71
- if (opts.schemaUrl) {
72
- debug('Fetching and writing remote schema "%s"', opts.schemaUrl)
73
- await getAndWriteJourneySchemaWorker({
74
- schemasPath: path.join(outputPath, 'schemaTypes'),
75
- useTypeScript,
76
- schemaUrl: opts.schemaUrl,
77
- })
78
- }
79
-
80
- spinner.succeed()
81
-
82
- // Merge global and template-specific plugins and dependencies
83
-
84
- // Resolve latest versions of Sanity-dependencies
85
- spinner = output.spinner('Resolving latest module versions').start()
86
- const dependencyVersions = await resolveLatestVersions({
87
- ...(isAppTemplate ? {} : studioDependencies.dependencies),
88
- ...(isAppTemplate ? {} : studioDependencies.devDependencies),
89
- ...template.dependencies,
90
- ...template.devDependencies,
91
- })
92
- spinner.succeed()
93
-
94
- // Use the resolved version for the given dependency
95
- const dependencies = Object.keys({
96
- ...(isAppTemplate ? {} : studioDependencies.dependencies),
97
- ...template.dependencies,
98
- }).reduce(
99
- (deps, dependency) => {
100
- deps[dependency] = dependencyVersions[dependency]
101
- return deps
102
- },
103
- {} as Record<string, string>,
104
- )
105
-
106
- const devDependencies = Object.keys({
107
- ...(isAppTemplate ? {} : studioDependencies.devDependencies),
108
- ...template.devDependencies,
109
- }).reduce(
110
- (deps, dependency) => {
111
- deps[dependency] = dependencyVersions[dependency]
112
- return deps
113
- },
114
- {} as Record<string, string>,
115
- )
116
-
117
- let packageJsonName: string = packageName
118
-
119
- /**
120
- * Currently app init doesn't ask for a name, so we use the last part of the path
121
- */
122
- if (isAppTemplate) {
123
- packageJsonName = deburr(path.basename(outputPath).toLowerCase())
124
- .replace(/\s+/g, '-')
125
- .replace(/[^a-z0-9-]/g, '')
126
- }
127
-
128
- // Now create a package manifest (`package.json`) with the merged dependencies
129
- spinner = output.spinner('Creating default project files').start()
130
- const packageManifest = await createPackageManifest({
131
- name: packageJsonName,
132
- dependencies,
133
- devDependencies,
134
- scripts: template.scripts,
135
- isAppTemplate,
136
- })
137
-
138
- // ...and a studio config (`sanity.config.[ts|js]`)
139
- const studioConfig = createStudioConfig({
140
- template: template.configTemplate,
141
- variables,
142
- })
143
-
144
- // ...and a CLI config (`sanity.cli.[ts|js]`)
145
- const cliConfig = isAppTemplate
146
- ? createAppCliConfig({
147
- entry: template.entry!,
148
- organizationId: variables.organizationId,
149
- })
150
- : createCliConfig({
151
- projectId: variables.projectId,
152
- dataset: variables.dataset,
153
- autoUpdates: variables.autoUpdates,
154
- })
155
-
156
- // Write non-template files to disc
157
- const codeExt = useTypeScript ? 'ts' : 'js'
158
- await Promise.all(
159
- [
160
- ...[
161
- isAppTemplate
162
- ? Promise.resolve(null)
163
- : writeFileIfNotExists(`sanity.config.${codeExt}`, studioConfig),
164
- ],
165
- writeFileIfNotExists(`sanity.cli.${codeExt}`, cliConfig),
166
- writeFileIfNotExists('package.json', packageManifest),
167
- ...[
168
- isAppTemplate
169
- ? Promise.resolve(null)
170
- : writeFileIfNotExists(
171
- 'eslint.config.mjs',
172
- `import studio from '@sanity/eslint-config-studio'\n\nexport default [...studio]\n`,
173
- ),
174
- ],
175
- ].filter(Boolean),
176
- )
177
-
178
- debug('Updating initial template metadata')
179
- await updateInitialTemplateMetadata(apiClient, variables.projectId, `cli-${templateName}`)
180
-
181
- // Finish up by providing init process with template-specific info
182
- spinner.succeed()
183
- return template
184
-
185
- async function writeFileIfNotExists(fileName: string, content: string): Promise<void> {
186
- const filePath = path.join(outputPath, fileName)
187
- try {
188
- await fs.writeFile(filePath, content, {flag: 'wx'})
189
- } catch (err) {
190
- if (err.code === 'EEXIST') {
191
- output.warn(`\n${chalk.yellow('⚠')} File "${filePath}" already exists, skipping`)
192
- } else {
193
- throw err
194
- }
195
- }
196
- }
197
- }
198
-
199
- function toTypeScriptPath(originalPath: string): string {
200
- return originalPath.replace(/\.js$/, '.ts')
201
- }
@@ -1,118 +0,0 @@
1
- import {mkdir} from 'node:fs/promises'
2
- import {join} from 'node:path'
3
-
4
- import {getMonoRepo, GitHubFileReader, validateTemplate} from '@sanity/template-validator'
5
- import {type Framework, frameworks} from '@vercel/frameworks'
6
- import {detectFrameworkRecord, LocalFileSystemDetector} from '@vercel/fs-detectors'
7
-
8
- import {debug} from '../../debug'
9
- import {type CliCommandContext} from '../../types'
10
- import {getDefaultPortForFramework} from '../../util/frameworkPort'
11
- import {
12
- applyEnvVariables,
13
- checkIfNeedsApiToken,
14
- downloadAndExtractRepo,
15
- generateSanityApiToken,
16
- getGitHubRawContentUrl,
17
- type RepoInfo,
18
- setCorsOrigin,
19
- tryApplyPackageName,
20
- } from '../../util/remoteTemplate'
21
- import {type GenerateConfigOptions} from './createStudioConfig'
22
- import {tryGitInit} from './git'
23
- import {updateInitialTemplateMetadata} from './updateInitialTemplateMetadata'
24
-
25
- export interface BootstrapRemoteOptions {
26
- outputPath: string
27
- repoInfo: RepoInfo
28
- bearerToken?: string
29
- packageName: string
30
- variables: GenerateConfigOptions['variables']
31
- }
32
-
33
- const SANITY_DEFAULT_PORT = 3333
34
- const READ_TOKEN_LABEL = 'Live Preview API'
35
- const WRITE_TOKEN_LABEL = 'App Write Token'
36
- const INITIAL_COMMIT_MESSAGE = 'Initial commit from Sanity CLI'
37
-
38
- export async function bootstrapRemoteTemplate(
39
- opts: BootstrapRemoteOptions,
40
- context: CliCommandContext,
41
- ): Promise<void> {
42
- const {outputPath, repoInfo, bearerToken, variables, packageName} = opts
43
- const {output, apiClient} = context
44
- const name = [repoInfo.username, repoInfo.name, repoInfo.filePath].filter(Boolean).join('/')
45
- const contentsUrl = getGitHubRawContentUrl(repoInfo)
46
- const headers: Record<string, string> = {}
47
- if (bearerToken) {
48
- headers.Authorization = `Bearer ${bearerToken}`
49
- }
50
- const spinner = output.spinner(`Bootstrapping files from template "${name}"`).start()
51
- const corsAdded: number[] = [SANITY_DEFAULT_PORT]
52
-
53
- debug('Validating remote template')
54
- const fileReader = new GitHubFileReader(contentsUrl, headers)
55
- const packages = await getMonoRepo(fileReader)
56
- const validation = await validateTemplate(fileReader, packages)
57
- if (!validation.isValid) {
58
- throw new Error(validation.errors.join('\n'))
59
- }
60
-
61
- debug('Create new directory "%s"', outputPath)
62
- await mkdir(outputPath, {recursive: true})
63
-
64
- debug('Downloading and extracting repo to %s', outputPath)
65
- await downloadAndExtractRepo(outputPath, repoInfo, bearerToken)
66
-
67
- debug('Checking if template needs read token')
68
- const needsReadToken = await Promise.all(
69
- (packages ?? ['']).map((pkg) => checkIfNeedsApiToken(join(outputPath, pkg), 'read')),
70
- ).then((results) => results.some(Boolean))
71
- const needsWriteToken = await Promise.all(
72
- (packages ?? ['']).map((pkg) => checkIfNeedsApiToken(join(outputPath, pkg), 'write')),
73
- ).then((results) => results.some(Boolean))
74
-
75
- debug('Applying environment variables')
76
- const readToken = needsReadToken
77
- ? await generateSanityApiToken(READ_TOKEN_LABEL, 'read', variables.projectId, apiClient)
78
- : undefined
79
- const writeToken = needsWriteToken
80
- ? await generateSanityApiToken(WRITE_TOKEN_LABEL, 'write', variables.projectId, apiClient)
81
- : undefined
82
-
83
- for (const pkg of packages ?? ['']) {
84
- const packagePath = join(outputPath, pkg)
85
- const packageFramework: Framework | null = await detectFrameworkRecord({
86
- fs: new LocalFileSystemDetector(packagePath),
87
- frameworkList: frameworks as readonly Framework[],
88
- })
89
-
90
- const port = getDefaultPortForFramework(packageFramework?.slug)
91
- if (corsAdded.includes(port) === false) {
92
- debug('Setting CORS origin to http://localhost:%d', port)
93
- await setCorsOrigin(`http://localhost:${port}`, variables.projectId, apiClient)
94
- corsAdded.push(port)
95
- }
96
-
97
- debug('Applying environment variables to %s', pkg)
98
- // Next.js uses `.env.local` for local environment variables
99
- const envName = packageFramework?.slug === 'nextjs' ? '.env.local' : '.env'
100
- await applyEnvVariables(packagePath, {...variables, readToken, writeToken}, envName)
101
- }
102
-
103
- debug('Setting package name to %s', packageName)
104
- await tryApplyPackageName(outputPath, packageName)
105
-
106
- debug('Initializing git repository')
107
- tryGitInit(outputPath, INITIAL_COMMIT_MESSAGE)
108
-
109
- debug('Updating initial template metadata')
110
- await updateInitialTemplateMetadata(apiClient, variables.projectId, `external-${name}`)
111
-
112
- spinner.succeed()
113
- if (corsAdded.length) {
114
- output.success(`CORS origins added (${corsAdded.map((p) => `localhost:${p}`).join(', ')})`)
115
- }
116
- if (readToken) output.success(`API token generated (${READ_TOKEN_LABEL})`)
117
- if (writeToken) output.success(`API token generated (${WRITE_TOKEN_LABEL})`)
118
- }
@@ -1,24 +0,0 @@
1
- import {processTemplate} from './processTemplate'
2
-
3
- const defaultAppTemplate = `
4
- import {defineCliConfig} from 'sanity/cli'
5
-
6
- export default defineCliConfig({
7
- app: {
8
- organizationId: '%organizationId%',
9
- entry: '%entry%',
10
- },
11
- })
12
- `
13
-
14
- export interface GenerateCliConfigOptions {
15
- organizationId?: string
16
- entry: string
17
- }
18
-
19
- export function createAppCliConfig(options: GenerateCliConfigOptions): string {
20
- return processTemplate({
21
- template: defaultAppTemplate,
22
- variables: options,
23
- })
24
- }
@@ -1,31 +0,0 @@
1
- import {processTemplate} from './processTemplate'
2
-
3
- const defaultTemplate = `
4
- import {defineCliConfig} from 'sanity/cli'
5
-
6
- export default defineCliConfig({
7
- api: {
8
- projectId: '%projectId%',
9
- dataset: '%dataset%'
10
- },
11
- /**
12
- * Enable auto-updates for studios.
13
- * Learn more at https://www.sanity.io/docs/cli#auto-updates
14
- */
15
- autoUpdates: __BOOL__autoUpdates__,
16
- })
17
- `
18
-
19
- export interface GenerateCliConfigOptions {
20
- projectId: string
21
- dataset: string
22
- autoUpdates: boolean
23
- }
24
-
25
- export function createCliConfig(options: GenerateCliConfigOptions): string {
26
- return processTemplate({
27
- template: defaultTemplate,
28
- variables: options,
29
- includeBooleanTransform: true,
30
- })
31
- }
@@ -1,102 +0,0 @@
1
- import sortObject from 'deep-sort-object'
2
-
3
- import {type PackageJson, type SanityJson} from '../../types'
4
-
5
- const manifestPropOrder = [
6
- 'name',
7
- 'private',
8
- 'version',
9
- 'description',
10
- 'main',
11
- 'author',
12
- 'license',
13
- 'scripts',
14
- 'keywords',
15
- 'dependencies',
16
- 'devDependencies',
17
- ]
18
-
19
- export function createPackageManifest(
20
- data: Omit<PackageJson, 'version'> & {gitRemote?: string} & {isAppTemplate?: boolean},
21
- ): string {
22
- const {isAppTemplate} = data
23
-
24
- const dependencies = data.dependencies ? {dependencies: sortObject(data.dependencies)} : {}
25
-
26
- const devDependencies = data.devDependencies
27
- ? {devDependencies: sortObject(data.devDependencies)}
28
- : {}
29
-
30
- // Don't write a prettier config for SDK apps; we want to allow developers to use their own
31
- const prettierConfig = isAppTemplate
32
- ? {}
33
- : {
34
- prettier: {
35
- semi: false,
36
- printWidth: 100,
37
- bracketSpacing: false,
38
- singleQuote: true,
39
- },
40
- }
41
-
42
- const pkg = {
43
- ...getCommonManifest(data),
44
-
45
- main: 'package.json',
46
- keywords: ['sanity'],
47
- scripts: data.scripts || {
48
- 'dev': 'sanity dev',
49
- 'start': 'sanity start',
50
- 'build': 'sanity build',
51
- 'deploy': 'sanity deploy',
52
- 'deploy-graphql': 'sanity graphql deploy',
53
- },
54
-
55
- ...dependencies,
56
- ...devDependencies,
57
- ...prettierConfig,
58
- }
59
-
60
- return serializeManifest(pkg)
61
- }
62
-
63
- function getCommonManifest(data: Omit<PackageJson, 'version'> & {gitRemote?: string}) {
64
- const pkg: PackageJson = {
65
- name: data.name,
66
- version: '1.0.0',
67
- description: data.description,
68
- author: data.author,
69
- license: data.license || 'UNLICENSED',
70
- devDependencies: {},
71
- }
72
-
73
- if (pkg.license === 'UNLICENSED') {
74
- pkg.private = true
75
- }
76
-
77
- if (data.gitRemote) {
78
- pkg.repository = {
79
- type: 'git',
80
- url: data.gitRemote,
81
- }
82
- }
83
-
84
- return pkg
85
- }
86
-
87
- function serializeManifest(src: PackageJson | SanityJson): string {
88
- const props = manifestPropOrder.concat(Object.keys(src))
89
- const ordered = props.reduce(
90
- (target, prop) => {
91
- const source = src as any
92
- if (typeof source[prop] !== 'undefined' && typeof target[prop] === 'undefined') {
93
- target[prop] = source[prop]
94
- }
95
-
96
- return target
97
- },
98
- {} as Record<string, any>,
99
- )
100
-
101
- return `${JSON.stringify(ordered, null, 2)}\n`
102
- }