@sanity/cli 3.65.1 → 3.65.2-corel.465

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/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.1",
3
+ "version": "3.65.2-corel.465+c829d7e227",
4
4
  "description": "Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets",
5
5
  "keywords": [
6
6
  "sanity",
@@ -57,22 +57,23 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "@babel/traverse": "^7.23.5",
60
- "@sanity/client": "^6.22.5",
61
- "@sanity/codegen": "3.65.1",
60
+ "@sanity/client": "^6.24.1",
61
+ "@sanity/codegen": "3.65.2-corel.465+c829d7e227",
62
62
  "@sanity/telemetry": "^0.7.7",
63
- "@sanity/util": "3.65.1",
63
+ "@sanity/util": "3.65.2-corel.465+c829d7e227",
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.0",
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
79
  "@repo/package.config": "3.65.1",
@@ -81,7 +82,7 @@
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.1",
85
+ "@sanity/types": "3.65.2-corel.465+c829d7e227",
85
86
  "@types/babel__traverse": "^7.20.5",
86
87
  "@types/configstore": "^5.0.1",
87
88
  "@types/cpx": "^1.5.2",
@@ -90,7 +91,7 @@
90
91
  "@types/inquirer": "^6.0.0",
91
92
  "@types/lodash": "^4.17.7",
92
93
  "@types/minimist": "^1.2.5",
93
- "@types/node": "^18.19.8",
94
+ "@types/node": "^22.10.0",
94
95
  "@types/rimraf": "^3.0.2",
95
96
  "@types/semver": "^7.5.6",
96
97
  "@types/semver-compare": "^1.0.1",
@@ -135,5 +136,5 @@
135
136
  "engines": {
136
137
  "node": ">=18"
137
138
  },
138
- "gitHead": "02d1e6c5520414ae61300dd45855a9ccf8f40915"
139
+ "gitHead": "c829d7e227cb84f27017ee21ddf21522a1fc32a7"
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 BootstrapOptions {
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 bootstrapTemplate(
32
- opts: BootstrapOptions,
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
- // Store template name metadata on project
146
- try {
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,74 @@
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
+ isCI?: boolean
27
+ }
28
+
29
+ const INITIAL_COMMIT_MESSAGE = 'Initial commit from Sanity CLI'
30
+
31
+ export async function bootstrapRemoteTemplate(
32
+ opts: BootstrapRemoteOptions,
33
+ context: CliCommandContext,
34
+ ): Promise<void> {
35
+ const {outputPath, repoInfo, bearerToken, variables, packageName, isCI} = opts
36
+ const {output, apiClient} = context
37
+ const name = [repoInfo.username, repoInfo.name, repoInfo.filePath].filter(Boolean).join('/')
38
+ const spinner = output.spinner(`Bootstrapping files from template "${name}"`).start()
39
+
40
+ debug('Validating remote template')
41
+ const packages = await getMonoRepo(repoInfo, bearerToken)
42
+ await validateRemoteTemplate(repoInfo, packages, bearerToken)
43
+
44
+ debug('Create new directory "%s"', outputPath)
45
+ await mkdir(outputPath, {recursive: true})
46
+
47
+ debug('Downloading and extracting repo to %s', outputPath)
48
+ await downloadAndExtractRepo(outputPath, repoInfo, bearerToken)
49
+
50
+ debug('Applying environment variables')
51
+ const readToken = await generateSanityApiReadToken(
52
+ isCI ? 'ci-remote-template-test-token-please-add-email-filter' : 'API Read Token',
53
+ variables.projectId,
54
+ apiClient,
55
+ )
56
+ const isNext = await isNextJsTemplate(outputPath)
57
+ const envName = isNext ? '.env.local' : '.env'
58
+
59
+ for (const folder of packages ?? ['']) {
60
+ const path = join(outputPath, folder)
61
+ await applyEnvVariables(path, {...variables, readToken}, envName)
62
+ }
63
+
64
+ debug('Setting package name to %s', packageName)
65
+ await tryApplyPackageName(outputPath, packageName)
66
+
67
+ debug('Initializing git repository')
68
+ tryGitInit(outputPath, INITIAL_COMMIT_MESSAGE)
69
+
70
+ debug('Updating initial template metadata')
71
+ await updateInitialTemplateMetadata(apiClient, variables.projectId, `external-${name}`)
72
+
73
+ spinner.succeed()
74
+ }
@@ -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 {type BootstrapOptions, bootstrapTemplate} from './bootstrapTemplate'
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'
@@ -68,19 +72,13 @@ import {
68
72
  } from './templates/nextjs'
69
73
 
70
74
  // eslint-disable-next-line no-process-env
71
- const isCI = process.env.CI
75
+ const isCI = Boolean(process.env.CI)
72
76
 
73
77
  /**
74
78
  * @deprecated - No longer used
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(`Env filename must start with .env`)
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
- print('Looks like you already have a Sanity-account. Sweet!\n')
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 (!typescriptOnly && typeof cliFlags.typescript === 'boolean') {
592
- useTypeScript = cliFlags.typescript
593
- } else if (!typescriptOnly && !unattended) {
594
- useTypeScript = await promptForTypeScript(prompt)
595
- trace.log({step: 'useTypeScript', selectedOption: useTypeScript ? 'yes' : 'no'})
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.datasetUrl && (await promptForDatasetImport(template.importPrompt))
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
- // record template files attempted to be created locally
627
- apiClient({api: {projectId: projectId}})
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 spinner = context.output.spinner('Fetching existing projects').start()
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,59 @@ 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
+ isCI,
1131
+ },
1132
+ context,
1133
+ )
1134
+ }
1135
+
1136
+ return bootstrapLocalTemplate(
1137
+ {
1138
+ outputPath,
1139
+ packageName: sluggedName,
1140
+ templateName,
1141
+ schemaUrl,
1142
+ useTypeScript,
1143
+ variables: bootstrapVariables,
1144
+ },
1145
+ context,
1146
+ )
1147
+ }
1148
+
1120
1149
  async function getProjectInfo(): Promise<ProjectDefaults & {outputPath: string}> {
1121
1150
  const specifiedPath = flags['output-path'] && path.resolve(flags['output-path'])
1122
1151
 
@@ -1479,6 +1508,16 @@ async function getPlanFromCoupon(apiClient: CliApiClient, couponCode: string): P
1479
1508
  return planId
1480
1509
  }
1481
1510
 
1511
+ async function getUserData(apiClient: CliApiClient): Promise<SanityUser> {
1512
+ return await apiClient({
1513
+ requireUser: true,
1514
+ requireProject: false,
1515
+ }).request({
1516
+ method: 'GET',
1517
+ uri: 'users/me',
1518
+ })
1519
+ }
1520
+
1482
1521
  async function getPlanFromId(apiClient: CliApiClient, planId: string): Promise<string> {
1483
1522
  const response = await apiClient({
1484
1523
  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, prompt} = context
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
- if (
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
+ }