@sanity/cli 3.65.1-export-comments.7 → 3.65.2-cops.39
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/lib/_chunks-cjs/cli.js +4125 -388
- package/lib/_chunks-cjs/cli.js.map +1 -1
- package/lib/index.d.mts +9 -0
- package/lib/index.d.ts +9 -0
- package/package.json +11 -10
- package/src/actions/init-project/{bootstrapTemplate.ts → bootstrapLocalTemplate.ts} +6 -19
- package/src/actions/init-project/bootstrapRemoteTemplate.ts +69 -0
- package/src/actions/init-project/initProject.ts +110 -72
- package/src/actions/init-project/updateInitialTemplateMetadata.ts +24 -0
- package/src/commands/init/initCommand.ts +7 -58
- package/src/types.ts +9 -0
- package/src/util/getProviderName.ts +9 -0
- package/src/util/remoteTemplate.ts +505 -0
- package/bin/xdg-open +0 -1066
package/lib/index.d.mts
CHANGED
@@ -445,6 +445,15 @@ export declare interface SanityModuleInternal {
|
|
445
445
|
}
|
446
446
|
}
|
447
447
|
|
448
|
+
export declare type SanityUser = {
|
449
|
+
id: string
|
450
|
+
name: string
|
451
|
+
email: string
|
452
|
+
profileImage?: string
|
453
|
+
tosAcceptedAt?: string
|
454
|
+
provider: 'google' | 'github' | 'sanity' | `saml-${string}`
|
455
|
+
}
|
456
|
+
|
448
457
|
export declare type SinglePrompt =
|
449
458
|
| (Omit<DistinctQuestion, 'name'> & {
|
450
459
|
type: 'list'
|
package/lib/index.d.ts
CHANGED
@@ -445,6 +445,15 @@ export declare interface SanityModuleInternal {
|
|
445
445
|
}
|
446
446
|
}
|
447
447
|
|
448
|
+
export declare type SanityUser = {
|
449
|
+
id: string
|
450
|
+
name: string
|
451
|
+
email: string
|
452
|
+
profileImage?: string
|
453
|
+
tosAcceptedAt?: string
|
454
|
+
provider: 'google' | 'github' | 'sanity' | `saml-${string}`
|
455
|
+
}
|
456
|
+
|
448
457
|
export declare type SinglePrompt =
|
449
458
|
| (Omit<DistinctQuestion, 'name'> & {
|
450
459
|
type: 'list'
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@sanity/cli",
|
3
|
-
"version": "3.65.
|
3
|
+
"version": "3.65.2-cops.39+eadc82ba20",
|
4
4
|
"description": "Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets",
|
5
5
|
"keywords": [
|
6
6
|
"sanity",
|
@@ -57,31 +57,32 @@
|
|
57
57
|
},
|
58
58
|
"dependencies": {
|
59
59
|
"@babel/traverse": "^7.23.5",
|
60
|
-
"@sanity/client": "^6.
|
61
|
-
"@sanity/codegen": "3.65.
|
60
|
+
"@sanity/client": "^6.24.0",
|
61
|
+
"@sanity/codegen": "3.65.2-cops.39+eadc82ba20",
|
62
62
|
"@sanity/telemetry": "^0.7.7",
|
63
|
-
"@sanity/util": "3.65.
|
63
|
+
"@sanity/util": "3.65.2-cops.39+eadc82ba20",
|
64
64
|
"chalk": "^4.1.2",
|
65
65
|
"debug": "^4.3.4",
|
66
66
|
"decompress": "^4.2.0",
|
67
67
|
"esbuild": "0.21.5",
|
68
68
|
"esbuild-register": "^3.5.0",
|
69
69
|
"get-it": "^8.6.5",
|
70
|
-
"groq-js": "^1.14.
|
70
|
+
"groq-js": "^1.14.1",
|
71
71
|
"pkg-dir": "^5.0.0",
|
72
72
|
"prettier": "^3.3.0",
|
73
73
|
"semver": "^7.3.5",
|
74
74
|
"silver-fleece": "1.1.0",
|
75
|
-
"validate-npm-package-name": "^3.0.0"
|
75
|
+
"validate-npm-package-name": "^3.0.0",
|
76
|
+
"yaml": "^2.6.1"
|
76
77
|
},
|
77
78
|
"devDependencies": {
|
78
|
-
"@repo/package.config": "3.65.
|
79
|
-
"@repo/test-config": "3.65.
|
79
|
+
"@repo/package.config": "3.65.1",
|
80
|
+
"@repo/test-config": "3.65.1",
|
80
81
|
"@rexxars/gitconfiglocal": "^3.0.1",
|
81
82
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
82
83
|
"@sanity/eslint-config-studio": "^4.0.0",
|
83
84
|
"@sanity/generate-help-url": "^3.0.0",
|
84
|
-
"@sanity/types": "3.65.
|
85
|
+
"@sanity/types": "3.65.2-cops.39+eadc82ba20",
|
85
86
|
"@types/babel__traverse": "^7.20.5",
|
86
87
|
"@types/configstore": "^5.0.1",
|
87
88
|
"@types/cpx": "^1.5.2",
|
@@ -135,5 +136,5 @@
|
|
135
136
|
"engines": {
|
136
137
|
"node": ">=18"
|
137
138
|
},
|
138
|
-
"gitHead": "
|
139
|
+
"gitHead": "eadc82ba200ce70835c6575afc5ab908826695f0"
|
139
140
|
}
|
@@ -14,8 +14,9 @@ import {createPackageManifest} from './createPackageManifest'
|
|
14
14
|
import {createStudioConfig, type GenerateConfigOptions} from './createStudioConfig'
|
15
15
|
import {type ProjectTemplate} from './initProject'
|
16
16
|
import templates from './templates'
|
17
|
+
import {updateInitialTemplateMetadata} from './updateInitialTemplateMetadata'
|
17
18
|
|
18
|
-
export interface
|
19
|
+
export interface BootstrapLocalOptions {
|
19
20
|
packageName: string
|
20
21
|
templateName: string
|
21
22
|
/**
|
@@ -28,8 +29,8 @@ export interface BootstrapOptions {
|
|
28
29
|
variables: GenerateConfigOptions['variables']
|
29
30
|
}
|
30
31
|
|
31
|
-
export async function
|
32
|
-
opts:
|
32
|
+
export async function bootstrapLocalTemplate(
|
33
|
+
opts: BootstrapLocalOptions,
|
33
34
|
context: CliCommandContext,
|
34
35
|
): Promise<ProjectTemplate> {
|
35
36
|
const {apiClient, cliRoot, output} = context
|
@@ -142,22 +143,8 @@ export async function bootstrapTemplate(
|
|
142
143
|
),
|
143
144
|
])
|
144
145
|
|
145
|
-
|
146
|
-
|
147
|
-
await apiClient({api: {projectId}}).request({
|
148
|
-
method: 'PATCH',
|
149
|
-
uri: `/projects/${projectId}`,
|
150
|
-
body: {metadata: {initialTemplate: `cli-${templateName}`}},
|
151
|
-
})
|
152
|
-
} catch (err: unknown) {
|
153
|
-
// Non-critical that we update this metadata, and user does not need to be aware
|
154
|
-
let message = typeof err === 'string' ? err : '<unknown error>'
|
155
|
-
if (err instanceof Error) {
|
156
|
-
message = err.message
|
157
|
-
}
|
158
|
-
|
159
|
-
debug('Failed to update initial template metadata for project: %s', message)
|
160
|
-
}
|
146
|
+
debug('Updating initial template metadata')
|
147
|
+
await updateInitialTemplateMetadata(apiClient, variables.projectId, `cli-${templateName}`)
|
161
148
|
|
162
149
|
// Finish up by providing init process with template-specific info
|
163
150
|
spinner.succeed()
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import {mkdir} from 'node:fs/promises'
|
2
|
+
import {join} from 'node:path'
|
3
|
+
|
4
|
+
import {debug} from '../../debug'
|
5
|
+
import {type CliCommandContext} from '../../types'
|
6
|
+
import {
|
7
|
+
applyEnvVariables,
|
8
|
+
downloadAndExtractRepo,
|
9
|
+
generateSanityApiReadToken,
|
10
|
+
getMonoRepo,
|
11
|
+
isNextJsTemplate,
|
12
|
+
type RepoInfo,
|
13
|
+
tryApplyPackageName,
|
14
|
+
validateRemoteTemplate,
|
15
|
+
} from '../../util/remoteTemplate'
|
16
|
+
import {type GenerateConfigOptions} from './createStudioConfig'
|
17
|
+
import {tryGitInit} from './git'
|
18
|
+
import {updateInitialTemplateMetadata} from './updateInitialTemplateMetadata'
|
19
|
+
|
20
|
+
export interface BootstrapRemoteOptions {
|
21
|
+
outputPath: string
|
22
|
+
repoInfo: RepoInfo
|
23
|
+
bearerToken?: string
|
24
|
+
packageName: string
|
25
|
+
variables: GenerateConfigOptions['variables']
|
26
|
+
}
|
27
|
+
|
28
|
+
const INITIAL_COMMIT_MESSAGE = 'Initial commit from Sanity CLI'
|
29
|
+
|
30
|
+
export async function bootstrapRemoteTemplate(
|
31
|
+
opts: BootstrapRemoteOptions,
|
32
|
+
context: CliCommandContext,
|
33
|
+
): Promise<void> {
|
34
|
+
const {outputPath, repoInfo, bearerToken, variables, packageName} = opts
|
35
|
+
const {output, apiClient} = context
|
36
|
+
const name = [repoInfo.username, repoInfo.name, repoInfo.filePath].filter(Boolean).join('/')
|
37
|
+
const spinner = output.spinner(`Bootstrapping files from template "${name}"`).start()
|
38
|
+
|
39
|
+
debug('Validating remote template')
|
40
|
+
const packages = await getMonoRepo(repoInfo, bearerToken)
|
41
|
+
await validateRemoteTemplate(repoInfo, packages, bearerToken)
|
42
|
+
|
43
|
+
debug('Create new directory "%s"', outputPath)
|
44
|
+
await mkdir(outputPath, {recursive: true})
|
45
|
+
|
46
|
+
debug('Downloading and extracting repo to %s', outputPath)
|
47
|
+
await downloadAndExtractRepo(outputPath, repoInfo, bearerToken)
|
48
|
+
|
49
|
+
debug('Applying environment variables')
|
50
|
+
const readToken = await generateSanityApiReadToken(variables.projectId, apiClient)
|
51
|
+
const isNext = await isNextJsTemplate(outputPath)
|
52
|
+
const envName = isNext ? '.env.local' : '.env'
|
53
|
+
|
54
|
+
for (const folder of packages ?? ['']) {
|
55
|
+
const path = join(outputPath, folder)
|
56
|
+
await applyEnvVariables(path, {...variables, readToken}, envName)
|
57
|
+
}
|
58
|
+
|
59
|
+
debug('Setting package name to %s', packageName)
|
60
|
+
await tryApplyPackageName(outputPath, packageName)
|
61
|
+
|
62
|
+
debug('Initializing git repository')
|
63
|
+
tryGitInit(outputPath, INITIAL_COMMIT_MESSAGE)
|
64
|
+
|
65
|
+
debug('Updating initial template metadata')
|
66
|
+
await updateInitialTemplateMetadata(apiClient, variables.projectId, `external-${name}`)
|
67
|
+
|
68
|
+
spinner.succeed()
|
69
|
+
}
|
@@ -35,17 +35,21 @@ import {
|
|
35
35
|
type CliCommandDefinition,
|
36
36
|
type SanityCore,
|
37
37
|
type SanityModuleInternal,
|
38
|
+
type SanityUser,
|
38
39
|
} from '../../types'
|
39
40
|
import {getClientWrapper} from '../../util/clientWrapper'
|
40
41
|
import {dynamicRequire} from '../../util/dynamicRequire'
|
41
42
|
import {getProjectDefaults, type ProjectDefaults} from '../../util/getProjectDefaults'
|
43
|
+
import {getProviderName} from '../../util/getProviderName'
|
42
44
|
import {getUserConfig} from '../../util/getUserConfig'
|
43
45
|
import {isCommandGroup} from '../../util/isCommandGroup'
|
44
46
|
import {isInteractive} from '../../util/isInteractive'
|
45
47
|
import {fetchJourneyConfig} from '../../util/journeyConfig'
|
48
|
+
import {checkIsRemoteTemplate, getGitHubRepoInfo, type RepoInfo} from '../../util/remoteTemplate'
|
46
49
|
import {login, type LoginFlags} from '../login/login'
|
47
50
|
import {createProject} from '../project/createProject'
|
48
|
-
import {
|
51
|
+
import {bootstrapLocalTemplate} from './bootstrapLocalTemplate'
|
52
|
+
import {bootstrapRemoteTemplate} from './bootstrapRemoteTemplate'
|
49
53
|
import {type GenerateConfigOptions} from './createStudioConfig'
|
50
54
|
import {absolutify, validateEmptyPath} from './fsUtils'
|
51
55
|
import {tryGitInit} from './git'
|
@@ -75,12 +79,6 @@ const isCI = process.env.CI
|
|
75
79
|
*/
|
76
80
|
export interface InitOptions {
|
77
81
|
template: string
|
78
|
-
// /**
|
79
|
-
// * Used for initializing a project from a server schema that is saved in the Journey API
|
80
|
-
// * This will override the `template` option.
|
81
|
-
// * @beta
|
82
|
-
// */
|
83
|
-
// journeyProjectId?: string
|
84
82
|
outputDir: string
|
85
83
|
name: string
|
86
84
|
displayName: string
|
@@ -144,6 +142,11 @@ export default async function initSanity(
|
|
144
142
|
const env = cliFlags.env
|
145
143
|
const packageManager = cliFlags['package-manager']
|
146
144
|
|
145
|
+
let remoteTemplateInfo: RepoInfo | undefined
|
146
|
+
if (cliFlags.template && checkIsRemoteTemplate(cliFlags.template)) {
|
147
|
+
remoteTemplateInfo = await getGitHubRepoInfo(cliFlags.template, cliFlags['template-token'])
|
148
|
+
}
|
149
|
+
|
147
150
|
let defaultConfig = cliFlags['dataset-default']
|
148
151
|
let showDefaultConfigPrompt = !defaultConfig
|
149
152
|
|
@@ -167,6 +170,12 @@ export default async function initSanity(
|
|
167
170
|
return
|
168
171
|
}
|
169
172
|
|
173
|
+
if (detectedFramework && detectedFramework.slug !== 'sanity' && remoteTemplateInfo) {
|
174
|
+
throw new Error(
|
175
|
+
`A remote template cannot be used with a detected framework. Detected: ${detectedFramework.name}`,
|
176
|
+
)
|
177
|
+
}
|
178
|
+
|
170
179
|
// Only allow either --project-plan or --coupon
|
171
180
|
if (intendedCoupon && intendedPlan) {
|
172
181
|
throw new Error(
|
@@ -253,25 +262,9 @@ export default async function initSanity(
|
|
253
262
|
}
|
254
263
|
const envFilename = typeof env === 'string' ? env : envFilenameDefault
|
255
264
|
if (!envFilename.startsWith('.env')) {
|
256
|
-
throw new Error(
|
265
|
+
throw new Error('Env filename must start with .env')
|
257
266
|
}
|
258
267
|
|
259
|
-
const usingBareOrEnv = cliFlags.bare || cliFlags.env
|
260
|
-
print(
|
261
|
-
cliFlags.quickstart
|
262
|
-
? "You're ejecting a remote Sanity project!"
|
263
|
-
: `You're setting up a new project!`,
|
264
|
-
)
|
265
|
-
print(`We'll make sure you have an account with Sanity.io. ${usingBareOrEnv ? '' : `Then we'll`}`)
|
266
|
-
if (!usingBareOrEnv) {
|
267
|
-
print('install an open-source JS content editor that connects to')
|
268
|
-
print('the real-time hosted API on Sanity.io. Hang on.\n')
|
269
|
-
}
|
270
|
-
print('Press ctrl + C at any time to quit.\n')
|
271
|
-
print('Prefer web interfaces to terminals?')
|
272
|
-
print('You can also set up best practice Sanity projects with')
|
273
|
-
print('your favorite frontends on https://www.sanity.io/templates\n')
|
274
|
-
|
275
268
|
// If the user isn't already authenticated, make it so
|
276
269
|
const userConfig = getUserConfig()
|
277
270
|
const hasToken = userConfig.get('authToken')
|
@@ -279,12 +272,28 @@ export default async function initSanity(
|
|
279
272
|
debug(hasToken ? 'User already has a token' : 'User has no token')
|
280
273
|
if (hasToken) {
|
281
274
|
trace.log({step: 'login', alreadyLoggedIn: true})
|
282
|
-
|
275
|
+
const user = await getUserData(apiClient)
|
276
|
+
print('')
|
277
|
+
print(
|
278
|
+
`${chalk.gray(" 👤 You're logged in as %s using %s")}`,
|
279
|
+
user.name,
|
280
|
+
getProviderName(user.provider),
|
281
|
+
)
|
282
|
+
print('')
|
283
283
|
} else if (!unattended) {
|
284
284
|
trace.log({step: 'login'})
|
285
285
|
await getOrCreateUser()
|
286
286
|
}
|
287
287
|
|
288
|
+
let introMessage = "Let's get you started with a new project"
|
289
|
+
if (cliFlags.quickstart) {
|
290
|
+
introMessage = "Let's get you started with remote Sanity project"
|
291
|
+
} else if (remoteTemplateInfo) {
|
292
|
+
introMessage = "Let's get you started with a remote Sanity template"
|
293
|
+
}
|
294
|
+
print(` ➡️ ${chalk.gray(introMessage)}`)
|
295
|
+
print('')
|
296
|
+
|
288
297
|
const flags = await prepareFlags()
|
289
298
|
// We're authenticated, now lets select or create a project
|
290
299
|
const {projectId, displayName, isFirstProject, datasetName, schemaUrl} = await getProjectDetails()
|
@@ -581,18 +590,20 @@ export default async function initSanity(
|
|
581
590
|
const templateName = await selectProjectTemplate()
|
582
591
|
trace.log({step: 'selectProjectTemplate', selectedOption: templateName})
|
583
592
|
const template = templates[templateName]
|
584
|
-
if (!template) {
|
593
|
+
if (!remoteTemplateInfo && !template) {
|
585
594
|
throw new Error(`Template "${templateName}" not found`)
|
586
595
|
}
|
587
596
|
|
588
597
|
// Use typescript?
|
589
|
-
const typescriptOnly = template.typescriptOnly === true
|
590
598
|
let useTypeScript = true
|
591
|
-
if (!
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
599
|
+
if (!remoteTemplateInfo && template) {
|
600
|
+
const typescriptOnly = template.typescriptOnly === true
|
601
|
+
if (!typescriptOnly && typeof cliFlags.typescript === 'boolean') {
|
602
|
+
useTypeScript = cliFlags.typescript
|
603
|
+
} else if (!typescriptOnly && !unattended) {
|
604
|
+
useTypeScript = await promptForTypeScript(prompt)
|
605
|
+
trace.log({step: 'useTypeScript', selectedOption: useTypeScript ? 'yes' : 'no'})
|
606
|
+
}
|
596
607
|
}
|
597
608
|
|
598
609
|
// we enable auto-updates by default, but allow users to specify otherwise
|
@@ -601,47 +612,15 @@ export default async function initSanity(
|
|
601
612
|
autoUpdates = cliFlags['auto-updates']
|
602
613
|
}
|
603
614
|
|
604
|
-
// Build a full set of resolved options
|
605
|
-
const templateOptions: BootstrapOptions = {
|
606
|
-
outputPath,
|
607
|
-
packageName: sluggedName,
|
608
|
-
templateName,
|
609
|
-
schemaUrl,
|
610
|
-
useTypeScript,
|
611
|
-
variables: {
|
612
|
-
autoUpdates,
|
613
|
-
dataset: datasetName,
|
614
|
-
projectId,
|
615
|
-
projectName: displayName || answers.projectName,
|
616
|
-
},
|
617
|
-
}
|
618
|
-
|
619
615
|
// If the template has a sample dataset, prompt the user whether or not we should import it
|
620
616
|
const shouldImport =
|
621
|
-
!unattended && template
|
617
|
+
!unattended && template?.datasetUrl && (await promptForDatasetImport(template.importPrompt))
|
622
618
|
|
623
619
|
trace.log({step: 'importTemplateDataset', selectedOption: shouldImport ? 'yes' : 'no'})
|
624
620
|
|
625
621
|
const [_, bootstrapPromise] = await Promise.allSettled([
|
626
|
-
|
627
|
-
|
628
|
-
.request<SanityProject>({uri: `/projects/${projectId}`})
|
629
|
-
.then((project: SanityProject) => {
|
630
|
-
if (!project?.metadata?.cliInitializedAt) {
|
631
|
-
return apiClient({api: {projectId}}).request({
|
632
|
-
method: 'PATCH',
|
633
|
-
uri: `/projects/${projectId}`,
|
634
|
-
body: {metadata: {cliInitializedAt: new Date().toISOString()}},
|
635
|
-
})
|
636
|
-
}
|
637
|
-
return Promise.resolve()
|
638
|
-
})
|
639
|
-
.catch(() => {
|
640
|
-
// Non-critical update
|
641
|
-
debug('Failed to update cliInitializedAt metadata')
|
642
|
-
}),
|
643
|
-
// Bootstrap Sanity, creating required project files, manifests etc
|
644
|
-
bootstrapTemplate(templateOptions, context),
|
622
|
+
updateProjectCliInitializedMetadata(),
|
623
|
+
bootstrapTemplate(),
|
645
624
|
])
|
646
625
|
|
647
626
|
if (bootstrapPromise.status === 'rejected' && bootstrapPromise.reason instanceof Error) {
|
@@ -823,21 +802,19 @@ export default async function initSanity(
|
|
823
802
|
isFirstProject: boolean
|
824
803
|
userAction: 'create' | 'select'
|
825
804
|
}> {
|
826
|
-
const
|
805
|
+
const client = apiClient({requireUser: true, requireProject: false})
|
827
806
|
let projects
|
828
807
|
let organizations: ProjectOrganization[]
|
808
|
+
|
829
809
|
try {
|
830
|
-
const client = apiClient({requireUser: true, requireProject: false})
|
831
810
|
const [allProjects, allOrgs] = await Promise.all([
|
832
811
|
client.projects.list({includeMembers: false}),
|
833
812
|
client.request({uri: '/organizations'}),
|
834
813
|
])
|
835
814
|
projects = allProjects.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
|
836
815
|
organizations = allOrgs
|
837
|
-
spinner.succeed()
|
838
816
|
} catch (err) {
|
839
817
|
if (unattended && flags.project) {
|
840
|
-
spinner.succeed()
|
841
818
|
return {
|
842
819
|
projectId: flags.project,
|
843
820
|
displayName: 'Unknown project',
|
@@ -845,7 +822,6 @@ export default async function initSanity(
|
|
845
822
|
userAction: 'select',
|
846
823
|
}
|
847
824
|
}
|
848
|
-
spinner.fail()
|
849
825
|
throw new Error(`Failed to communicate with the Sanity API:\n${err.message}`)
|
850
826
|
}
|
851
827
|
|
@@ -1117,6 +1093,58 @@ export default async function initSanity(
|
|
1117
1093
|
})
|
1118
1094
|
}
|
1119
1095
|
|
1096
|
+
async function updateProjectCliInitializedMetadata() {
|
1097
|
+
try {
|
1098
|
+
const client = apiClient({api: {projectId}})
|
1099
|
+
const project = await client.request<SanityProject>({uri: `/projects/${projectId}`})
|
1100
|
+
|
1101
|
+
if (!project?.metadata?.cliInitializedAt) {
|
1102
|
+
await client.request({
|
1103
|
+
method: 'PATCH',
|
1104
|
+
uri: `/projects/${projectId}`,
|
1105
|
+
body: {metadata: {cliInitializedAt: new Date().toISOString()}},
|
1106
|
+
})
|
1107
|
+
}
|
1108
|
+
} catch (err) {
|
1109
|
+
// Non-critical update
|
1110
|
+
debug('Failed to update cliInitializedAt metadata')
|
1111
|
+
}
|
1112
|
+
}
|
1113
|
+
|
1114
|
+
async function bootstrapTemplate() {
|
1115
|
+
const bootstrapVariables: GenerateConfigOptions['variables'] = {
|
1116
|
+
autoUpdates,
|
1117
|
+
dataset: datasetName,
|
1118
|
+
projectId,
|
1119
|
+
projectName: displayName || answers.projectName,
|
1120
|
+
}
|
1121
|
+
|
1122
|
+
if (remoteTemplateInfo) {
|
1123
|
+
return bootstrapRemoteTemplate(
|
1124
|
+
{
|
1125
|
+
outputPath,
|
1126
|
+
packageName: sluggedName,
|
1127
|
+
repoInfo: remoteTemplateInfo,
|
1128
|
+
bearerToken: cliFlags['template-token'],
|
1129
|
+
variables: bootstrapVariables,
|
1130
|
+
},
|
1131
|
+
context,
|
1132
|
+
)
|
1133
|
+
}
|
1134
|
+
|
1135
|
+
return bootstrapLocalTemplate(
|
1136
|
+
{
|
1137
|
+
outputPath,
|
1138
|
+
packageName: sluggedName,
|
1139
|
+
templateName,
|
1140
|
+
schemaUrl,
|
1141
|
+
useTypeScript,
|
1142
|
+
variables: bootstrapVariables,
|
1143
|
+
},
|
1144
|
+
context,
|
1145
|
+
)
|
1146
|
+
}
|
1147
|
+
|
1120
1148
|
async function getProjectInfo(): Promise<ProjectDefaults & {outputPath: string}> {
|
1121
1149
|
const specifiedPath = flags['output-path'] && path.resolve(flags['output-path'])
|
1122
1150
|
|
@@ -1479,6 +1507,16 @@ async function getPlanFromCoupon(apiClient: CliApiClient, couponCode: string): P
|
|
1479
1507
|
return planId
|
1480
1508
|
}
|
1481
1509
|
|
1510
|
+
async function getUserData(apiClient: CliApiClient): Promise<SanityUser> {
|
1511
|
+
return await apiClient({
|
1512
|
+
requireUser: true,
|
1513
|
+
requireProject: false,
|
1514
|
+
}).request({
|
1515
|
+
method: 'GET',
|
1516
|
+
uri: 'users/me',
|
1517
|
+
})
|
1518
|
+
}
|
1519
|
+
|
1482
1520
|
async function getPlanFromId(apiClient: CliApiClient, planId: string): Promise<string> {
|
1483
1521
|
const response = await apiClient({
|
1484
1522
|
requireUser: false,
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import {debug} from '../../debug'
|
2
|
+
import {type CliApiClient} from '../../types'
|
3
|
+
|
4
|
+
export async function updateInitialTemplateMetadata(
|
5
|
+
apiClient: CliApiClient,
|
6
|
+
projectId: string,
|
7
|
+
templateName: string,
|
8
|
+
): Promise<void> {
|
9
|
+
try {
|
10
|
+
await apiClient({api: {projectId}}).request({
|
11
|
+
method: 'PATCH',
|
12
|
+
uri: `/projects/${projectId}`,
|
13
|
+
body: {metadata: {initialTemplate: templateName}},
|
14
|
+
})
|
15
|
+
} catch (err: unknown) {
|
16
|
+
// Non-critical that we update this metadata, and user does not need to be aware
|
17
|
+
let message = typeof err === 'string' ? err : '<unknown error>'
|
18
|
+
if (err instanceof Error) {
|
19
|
+
message = err.message
|
20
|
+
}
|
21
|
+
|
22
|
+
debug('Failed to update initial template metadata for project: %s', message)
|
23
|
+
}
|
24
|
+
}
|
@@ -58,6 +58,11 @@ export interface InitFlags {
|
|
58
58
|
'project'?: string
|
59
59
|
'dataset'?: string
|
60
60
|
'template'?: string
|
61
|
+
/**
|
62
|
+
* Used for accessing private GitHub repo templates
|
63
|
+
* @beta
|
64
|
+
*/
|
65
|
+
'template-token'?: string
|
61
66
|
|
62
67
|
'visibility'?: string
|
63
68
|
'typescript'?: boolean
|
@@ -97,11 +102,8 @@ export const initCommand: CliCommandDefinition<InitFlags> = {
|
|
97
102
|
description: 'Initializes a new Sanity Studio and/or project',
|
98
103
|
helpText,
|
99
104
|
action: async (args, context) => {
|
100
|
-
const {output, chalk
|
105
|
+
const {output, chalk} = context
|
101
106
|
const [type] = args.argsWithoutOptions
|
102
|
-
const unattended = args.extOptions.y || args.extOptions.yes
|
103
|
-
|
104
|
-
const warn = (msg: string) => output.warn(chalk.yellow.bgBlack(msg))
|
105
107
|
|
106
108
|
// `sanity init plugin`
|
107
109
|
if (type === 'plugin') {
|
@@ -116,68 +118,15 @@ export const initCommand: CliCommandDefinition<InitFlags> = {
|
|
116
118
|
return Promise.reject(new Error(`Unknown init type "${type}"`))
|
117
119
|
}
|
118
120
|
|
119
|
-
// `npm create sanity` (regular v3 init)
|
120
|
-
|
121
121
|
const detectedFramework: Framework | null = await detectFrameworkRecord({
|
122
122
|
fs: new LocalFileSystemDetector(process.cwd()),
|
123
123
|
frameworkList: frameworks as readonly Framework[],
|
124
124
|
})
|
125
125
|
|
126
|
-
|
127
|
-
args.argv.includes('--from-create') ||
|
128
|
-
args.argv.includes('--env') ||
|
129
|
-
args.argv.includes('--bare') ||
|
130
|
-
detectedFramework?.slug === 'nextjs'
|
131
|
-
) {
|
132
|
-
return initProject(args, {
|
133
|
-
...context,
|
134
|
-
detectedFramework,
|
135
|
-
})
|
136
|
-
}
|
137
|
-
|
138
|
-
// `sanity init` (v2 style)
|
139
|
-
warn('╭────────────────────────────────────────────────────────────╮')
|
140
|
-
warn('│ │')
|
141
|
-
warn("│ Welcome to Sanity! It looks like you're following │")
|
142
|
-
warn('│ instructions for Sanity Studio v2, but the version you │')
|
143
|
-
warn('│ have installed is the latest - Sanity Studio v3. │')
|
144
|
-
warn('│ │')
|
145
|
-
warn('│ In Sanity Studio v3, new projects are created by running │')
|
146
|
-
warn('│ [npm create sanity@latest]. For more information, see │')
|
147
|
-
warn('│ https://www.sanity.io/help/studio-v2-vs-v3 │')
|
148
|
-
warn('│ │')
|
149
|
-
warn('╰────────────────────────────────────────────────────────────╯')
|
150
|
-
warn('') // Newline to separate from other output
|
151
|
-
const continueV3Init = unattended
|
152
|
-
? true
|
153
|
-
: await prompt.single({
|
154
|
-
message: 'Continue creating a Sanity Studio v3 project?',
|
155
|
-
type: 'confirm',
|
156
|
-
})
|
157
|
-
|
158
|
-
// Fall back
|
159
|
-
if (!continueV3Init) {
|
160
|
-
// Indicate that the operation did not succeed as expected
|
161
|
-
// eslint-disable-next-line no-process-exit
|
162
|
-
process.exit(1)
|
163
|
-
}
|
164
|
-
|
165
|
-
const returnVal = await initProject(args, {
|
126
|
+
return initProject(args, {
|
166
127
|
...context,
|
167
128
|
detectedFramework,
|
168
|
-
}).catch((err) => {
|
169
|
-
return Promise.reject(err)
|
170
129
|
})
|
171
|
-
|
172
|
-
warn('╭────────────────────────────────────────────────────────────╮')
|
173
|
-
warn('│ │')
|
174
|
-
warn('│ To learn how commands have changed from Studio v2 to v3, │')
|
175
|
-
warn('│ see https://www.sanity.io/help/studio-v2-vs-v3 │')
|
176
|
-
warn('│ │')
|
177
|
-
warn('╰────────────────────────────────────────────────────────────╯')
|
178
|
-
warn('') // Newline to separate from other output
|
179
|
-
|
180
|
-
return returnVal
|
181
130
|
},
|
182
131
|
}
|
183
132
|
|
package/src/types.ts
CHANGED
@@ -349,3 +349,12 @@ export interface CliConfig {
|
|
349
349
|
export type UserViteConfig =
|
350
350
|
| InlineConfig
|
351
351
|
| ((config: InlineConfig, env: ConfigEnv) => InlineConfig | Promise<InlineConfig>)
|
352
|
+
|
353
|
+
export type SanityUser = {
|
354
|
+
id: string
|
355
|
+
name: string
|
356
|
+
email: string
|
357
|
+
profileImage?: string
|
358
|
+
tosAcceptedAt?: string
|
359
|
+
provider: 'google' | 'github' | 'sanity' | `saml-${string}`
|
360
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import {type SanityUser} from '../types'
|
2
|
+
|
3
|
+
export function getProviderName(provider: SanityUser['provider']) {
|
4
|
+
if (provider === 'google') return 'Google'
|
5
|
+
if (provider === 'github') return 'GitHub'
|
6
|
+
if (provider === 'sanity') return 'Email'
|
7
|
+
if (provider.startsWith('saml-')) return 'SAML'
|
8
|
+
return provider
|
9
|
+
}
|