@sanity/cli 3.74.0 → 3.74.2-corel.18

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
@@ -114,6 +114,14 @@ export declare interface CliConfig {
114
114
  vite?: UserViteConfig
115
115
  autoUpdates?: boolean
116
116
  studioHost?: string
117
+ /**
118
+ * Parameter used to configure other kinds of applications.
119
+ * Signals to `sanity` commands that this is not a studio.
120
+ * @internal
121
+ */
122
+ __experimental_coreAppConfiguration?: {
123
+ appLocation?: string
124
+ }
117
125
  }
118
126
 
119
127
  declare type CliConfigResult =
@@ -357,6 +365,7 @@ export declare function loadEnv(
357
365
  export declare interface PackageJson {
358
366
  name: string
359
367
  version: string
368
+ scripts?: Record<string, string>
360
369
  description?: string
361
370
  author?: string
362
371
  license?: string
package/lib/index.d.ts CHANGED
@@ -114,6 +114,14 @@ export declare interface CliConfig {
114
114
  vite?: UserViteConfig
115
115
  autoUpdates?: boolean
116
116
  studioHost?: string
117
+ /**
118
+ * Parameter used to configure other kinds of applications.
119
+ * Signals to `sanity` commands that this is not a studio.
120
+ * @internal
121
+ */
122
+ __experimental_coreAppConfiguration?: {
123
+ appLocation?: string
124
+ }
117
125
  }
118
126
 
119
127
  declare type CliConfigResult =
@@ -357,6 +365,7 @@ export declare function loadEnv(
357
365
  export declare interface PackageJson {
358
366
  name: string
359
367
  version: string
368
+ scripts?: Record<string, string>
360
369
  description?: string
361
370
  author?: string
362
371
  license?: string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli",
3
- "version": "3.74.0",
3
+ "version": "3.74.2-corel.18+be0fcc993a",
4
4
  "description": "Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets",
5
5
  "keywords": [
6
6
  "sanity",
@@ -58,10 +58,10 @@
58
58
  "dependencies": {
59
59
  "@babel/traverse": "^7.23.5",
60
60
  "@sanity/client": "^6.27.2",
61
- "@sanity/codegen": "3.74.0",
61
+ "@sanity/codegen": "3.74.2-corel.18+be0fcc993a",
62
62
  "@sanity/telemetry": "^0.7.7",
63
63
  "@sanity/template-validator": "^2.4.0",
64
- "@sanity/util": "3.74.0",
64
+ "@sanity/util": "3.74.2-corel.18+be0fcc993a",
65
65
  "chalk": "^4.1.2",
66
66
  "debug": "^4.3.4",
67
67
  "decompress": "^4.2.0",
@@ -75,13 +75,13 @@
75
75
  "validate-npm-package-name": "^3.0.0"
76
76
  },
77
77
  "devDependencies": {
78
- "@repo/package.config": "3.74.0",
79
- "@repo/test-config": "3.74.0",
78
+ "@repo/package.config": "3.74.1",
79
+ "@repo/test-config": "3.74.1",
80
80
  "@rexxars/gitconfiglocal": "^3.0.1",
81
81
  "@rollup/plugin-node-resolve": "^15.2.3",
82
82
  "@sanity/eslint-config-studio": "^4.0.0",
83
83
  "@sanity/generate-help-url": "^3.0.0",
84
- "@sanity/types": "3.74.0",
84
+ "@sanity/types": "3.74.2-corel.18+be0fcc993a",
85
85
  "@types/babel__traverse": "^7.20.5",
86
86
  "@types/configstore": "^5.0.1",
87
87
  "@types/cpx": "^1.5.2",
@@ -126,12 +126,12 @@
126
126
  "semver-compare": "^1.0.0",
127
127
  "tar": "^6.1.11",
128
128
  "vite": "^6.0.11",
129
- "vitest": "^2.1.9",
129
+ "vitest": "^3.0.5",
130
130
  "which": "^2.0.2",
131
131
  "xdg-basedir": "^4.0.0"
132
132
  },
133
133
  "engines": {
134
134
  "node": ">=18"
135
135
  },
136
- "gitHead": "572200924cb755b08f1f90663166a88e774cc1e5"
136
+ "gitHead": "be0fcc993aa614f9ac46b6172bb418257a4e81b3"
137
137
  }
@@ -10,8 +10,10 @@ import {copy} from '../../util/copy'
10
10
  import {getAndWriteJourneySchemaWorker} from '../../util/journeyConfig'
11
11
  import {resolveLatestVersions} from '../../util/resolveLatestVersions'
12
12
  import {createCliConfig} from './createCliConfig'
13
+ import {createCoreAppCliConfig} from './createCoreAppCliConfig'
13
14
  import {createPackageManifest} from './createPackageManifest'
14
15
  import {createStudioConfig, type GenerateConfigOptions} from './createStudioConfig'
16
+ import {determineCoreAppTemplate} from './determineCoreAppTemplate'
15
17
  import {type ProjectTemplate} from './initProject'
16
18
  import templates from './templates'
17
19
  import {updateInitialTemplateMetadata} from './updateInitialTemplateMetadata'
@@ -36,9 +38,9 @@ export async function bootstrapLocalTemplate(
36
38
  const {apiClient, cliRoot, output} = context
37
39
  const templatesDir = path.join(cliRoot, 'templates')
38
40
  const {outputPath, templateName, useTypeScript, packageName, variables} = opts
39
- const {projectId} = variables
40
41
  const sourceDir = path.join(templatesDir, templateName)
41
42
  const sharedDir = path.join(templatesDir, 'shared')
43
+ const isCoreAppTemplate = determineCoreAppTemplate(templateName)
42
44
 
43
45
  // Check that we have a template info file (dependencies, plugins etc)
44
46
  const template = templates[templateName]
@@ -81,15 +83,16 @@ export async function bootstrapLocalTemplate(
81
83
  // Resolve latest versions of Sanity-dependencies
82
84
  spinner = output.spinner('Resolving latest module versions').start()
83
85
  const dependencyVersions = await resolveLatestVersions({
84
- ...studioDependencies.dependencies,
85
- ...studioDependencies.devDependencies,
86
+ ...(isCoreAppTemplate ? {} : studioDependencies.dependencies),
87
+ ...(isCoreAppTemplate ? {} : studioDependencies.devDependencies),
86
88
  ...(template.dependencies || {}),
89
+ ...(template.devDependencies || {}),
87
90
  })
88
91
  spinner.succeed()
89
92
 
90
93
  // Use the resolved version for the given dependency
91
94
  const dependencies = Object.keys({
92
- ...studioDependencies.dependencies,
95
+ ...(isCoreAppTemplate ? {} : studioDependencies.dependencies),
93
96
  ...template.dependencies,
94
97
  }).reduce(
95
98
  (deps, dependency) => {
@@ -100,7 +103,7 @@ export async function bootstrapLocalTemplate(
100
103
  )
101
104
 
102
105
  const devDependencies = Object.keys({
103
- ...studioDependencies.devDependencies,
106
+ ...(isCoreAppTemplate ? {} : studioDependencies.devDependencies),
104
107
  ...template.devDependencies,
105
108
  }).reduce(
106
109
  (deps, dependency) => {
@@ -116,32 +119,41 @@ export async function bootstrapLocalTemplate(
116
119
  name: packageName,
117
120
  dependencies,
118
121
  devDependencies,
122
+ scripts: template.scripts,
119
123
  })
120
124
 
121
125
  // ...and a studio config (`sanity.config.[ts|js]`)
122
- const studioConfig = await createStudioConfig({
126
+ const studioConfig = createStudioConfig({
123
127
  template: template.configTemplate,
124
128
  variables,
125
129
  })
126
130
 
127
131
  // ...and a CLI config (`sanity.cli.[ts|js]`)
128
- const cliConfig = await createCliConfig({
129
- projectId: variables.projectId,
130
- dataset: variables.dataset,
131
- autoUpdates: variables.autoUpdates,
132
- })
132
+ const cliConfig = isCoreAppTemplate
133
+ ? createCoreAppCliConfig({appLocation: template.appLocation!})
134
+ : createCliConfig({
135
+ projectId: variables.projectId,
136
+ dataset: variables.dataset,
137
+ autoUpdates: variables.autoUpdates,
138
+ })
133
139
 
134
140
  // Write non-template files to disc
135
141
  const codeExt = useTypeScript ? 'ts' : 'js'
136
- await Promise.all([
137
- writeFileIfNotExists(`sanity.config.${codeExt}`, studioConfig),
138
- writeFileIfNotExists(`sanity.cli.${codeExt}`, cliConfig),
139
- writeFileIfNotExists('package.json', packageManifest),
140
- writeFileIfNotExists(
141
- 'eslint.config.mjs',
142
- `import studio from '@sanity/eslint-config-studio'\n\nexport default [...studio]\n`,
143
- ),
144
- ])
142
+ await Promise.all(
143
+ [
144
+ ...[
145
+ isCoreAppTemplate
146
+ ? Promise.resolve(null)
147
+ : writeFileIfNotExists(`sanity.config.${codeExt}`, studioConfig),
148
+ ],
149
+ writeFileIfNotExists(`sanity.cli.${codeExt}`, cliConfig),
150
+ writeFileIfNotExists('package.json', packageManifest),
151
+ writeFileIfNotExists(
152
+ 'eslint.config.mjs',
153
+ `import studio from '@sanity/eslint-config-studio'\n\nexport default [...studio]\n`,
154
+ ),
155
+ ].filter(Boolean),
156
+ )
145
157
 
146
158
  debug('Updating initial template metadata')
147
159
  await updateInitialTemplateMetadata(apiClient, variables.projectId, `cli-${templateName}`)
@@ -1,6 +1,4 @@
1
- import traverse from '@babel/traverse'
2
- import {parse, print} from 'recast'
3
- import * as parser from 'recast/parsers/typescript'
1
+ import {processTemplate} from './processTemplate'
4
2
 
5
3
  const defaultTemplate = `
6
4
  import {defineCliConfig} from 'sanity/cli'
@@ -25,49 +23,9 @@ export interface GenerateCliConfigOptions {
25
23
  }
26
24
 
27
25
  export function createCliConfig(options: GenerateCliConfigOptions): string {
28
- const variables = options
29
- const template = defaultTemplate.trimStart()
30
- const ast = parse(template, {parser})
31
-
32
- traverse(ast, {
33
- StringLiteral: {
34
- enter({node}) {
35
- const value = node.value
36
- if (!value.startsWith('%') || !value.endsWith('%')) {
37
- return
38
- }
39
- const variableName = value.slice(1, -1) as keyof GenerateCliConfigOptions
40
- if (!(variableName in variables)) {
41
- throw new Error(`Template variable '${value}' not defined`)
42
- }
43
- const newValue = variables[variableName]
44
- /*
45
- * although there are valid non-strings in our config,
46
- * they're not in StringLiteral nodes, so assume undefined
47
- */
48
- node.value = typeof newValue === 'string' ? newValue : ''
49
- },
50
- },
51
- Identifier: {
52
- enter(path) {
53
- if (!path.node.name.startsWith('__BOOL__')) {
54
- return
55
- }
56
- const variableName = path.node.name.replace(
57
- /^__BOOL__(.+?)__$/,
58
- '$1',
59
- ) as keyof GenerateCliConfigOptions
60
- if (!(variableName in variables)) {
61
- throw new Error(`Template variable '${variableName}' not defined`)
62
- }
63
- const value = variables[variableName]
64
- if (typeof value !== 'boolean') {
65
- throw new Error(`Expected boolean value for '${variableName}'`)
66
- }
67
- path.replaceWith({type: 'BooleanLiteral', value})
68
- },
69
- },
26
+ return processTemplate({
27
+ template: defaultTemplate,
28
+ variables: options,
29
+ includeBooleanTransform: true,
70
30
  })
71
-
72
- return print(ast, {quote: 'single'}).code
73
31
  }
@@ -0,0 +1,23 @@
1
+ import {processTemplate} from './processTemplate'
2
+
3
+ const defaultCoreAppTemplate = `
4
+ import {defineCliConfig} from 'sanity/cli'
5
+
6
+ export default defineCliConfig({
7
+ __experimental_coreAppConfiguration: {
8
+ appLocation: '%appLocation%'
9
+ },
10
+ })
11
+ `
12
+
13
+ export interface GenerateCliConfigOptions {
14
+ organizationId?: string
15
+ appLocation: string
16
+ }
17
+
18
+ export function createCoreAppCliConfig(options: GenerateCliConfigOptions): string {
19
+ return processTemplate({
20
+ template: defaultCoreAppTemplate,
21
+ variables: options,
22
+ })
23
+ }
@@ -29,7 +29,7 @@ export function createPackageManifest(
29
29
 
30
30
  main: 'package.json',
31
31
  keywords: ['sanity'],
32
- scripts: {
32
+ scripts: data.scripts || {
33
33
  'dev': 'sanity dev',
34
34
  'start': 'sanity start',
35
35
  'build': 'sanity build',
@@ -1,6 +1,4 @@
1
- import traverse from '@babel/traverse'
2
- import {parse, print} from 'recast'
3
- import * as parser from 'recast/parsers/typescript'
1
+ import {processTemplate} from './processTemplate'
4
2
 
5
3
  const defaultTemplate = `
6
4
  import {defineConfig} from 'sanity'
@@ -47,29 +45,8 @@ export function createStudioConfig(options: GenerateConfigOptions): string {
47
45
  return options.template(variables).trimStart()
48
46
  }
49
47
 
50
- const template = (options.template || defaultTemplate).trimStart()
51
- const ast = parse(template, {parser})
52
- traverse(ast, {
53
- StringLiteral: {
54
- enter({node}) {
55
- const value = node.value
56
- if (!value.startsWith('%') || !value.endsWith('%')) {
57
- return
58
- }
59
-
60
- const variableName = value.slice(1, -1) as keyof GenerateConfigOptions['variables']
61
- if (!(variableName in variables)) {
62
- throw new Error(`Template variable '${value}' not defined`)
63
- }
64
- const newValue = variables[variableName]
65
- /*
66
- * although there are valid non-strings in our config,
67
- * they're not in this template, so assume undefined
68
- */
69
- node.value = typeof newValue === 'string' ? newValue : ''
70
- },
71
- },
48
+ return processTemplate({
49
+ template: options.template || defaultTemplate,
50
+ variables,
72
51
  })
73
-
74
- return print(ast, {quote: 'single'}).code
75
52
  }
@@ -0,0 +1,13 @@
1
+ const coreAppTemplates = ['core-app']
2
+
3
+ /**
4
+ * Determine if a given template is a studio template.
5
+ * This function may need to be more robust once we
6
+ * introduce remote templates, for example.
7
+ *
8
+ * @param templateName - Name of the template
9
+ * @returns boolean indicating if the template is a studio template
10
+ */
11
+ export function determineCoreAppTemplate(templateName: string): boolean {
12
+ return coreAppTemplates.includes(templateName)
13
+ }
@@ -49,6 +49,7 @@ import {createProject} from '../project/createProject'
49
49
  import {bootstrapLocalTemplate} from './bootstrapLocalTemplate'
50
50
  import {bootstrapRemoteTemplate} from './bootstrapRemoteTemplate'
51
51
  import {type GenerateConfigOptions} from './createStudioConfig'
52
+ import {determineCoreAppTemplate} from './determineCoreAppTemplate'
52
53
  import {absolutify, validateEmptyPath} from './fsUtils'
53
54
  import {tryGitInit} from './git'
54
55
  import {promptForDatasetName} from './promptForDatasetName'
@@ -97,6 +98,8 @@ export interface ProjectTemplate {
97
98
  importPrompt?: string
98
99
  configTemplate?: string | ((variables: GenerateConfigOptions['variables']) => string)
99
100
  typescriptOnly?: boolean
101
+ appLocation?: string
102
+ scripts?: Record<string, string>
100
103
  }
101
104
 
102
105
  export interface ProjectOrganization {
@@ -271,6 +274,9 @@ export default async function initSanity(
271
274
  print('')
272
275
 
273
276
  const flags = await prepareFlags()
277
+ // skip project / dataset prompting
278
+ const isCoreAppTemplate = cliFlags.template ? determineCoreAppTemplate(cliFlags.template) : false // Default to false
279
+
274
280
  // We're authenticated, now lets select or create a project
275
281
  const {projectId, displayName, isFirstProject, datasetName, schemaUrl} = await getProjectDetails()
276
282
 
@@ -655,11 +661,15 @@ export default async function initSanity(
655
661
  const isCurrentDir = outputPath === process.cwd()
656
662
  if (isCurrentDir) {
657
663
  print(`\n${chalk.green('Success!')} Now, use this command to continue:\n`)
658
- print(`${chalk.cyan(devCommand)} - to run Sanity Studio\n`)
664
+ print(
665
+ `${chalk.cyan(devCommand)} - to run ${isCoreAppTemplate ? 'your Sanity application' : 'Sanity Studio'}\n`,
666
+ )
659
667
  } else {
660
668
  print(`\n${chalk.green('Success!')} Now, use these commands to continue:\n`)
661
669
  print(`First: ${chalk.cyan(`cd ${outputPath}`)} - to enter project’s directory`)
662
- print(`Then: ${chalk.cyan(devCommand)} - to run Sanity Studio\n`)
670
+ print(
671
+ `Then: ${chalk.cyan(devCommand)} -to run ${isCoreAppTemplate ? 'your Sanity application' : 'Sanity Studio'}\n`,
672
+ )
663
673
  }
664
674
 
665
675
  print(`Other helpful commands`)
@@ -720,6 +730,15 @@ export default async function initSanity(
720
730
  return data
721
731
  }
722
732
 
733
+ if (isCoreAppTemplate) {
734
+ return {
735
+ projectId: '',
736
+ displayName: '',
737
+ isFirstProject: false,
738
+ datasetName: '',
739
+ }
740
+ }
741
+
723
742
  debug('Prompting user to select or create a project')
724
743
  const project = await getOrCreateProject()
725
744
  debug(`Project with name ${project.displayName} selected`)
@@ -0,0 +1,55 @@
1
+ import traverse from '@babel/traverse'
2
+ import {parse, print} from 'recast'
3
+ import * as parser from 'recast/parsers/typescript'
4
+
5
+ interface TemplateOptions<T> {
6
+ template: string
7
+ variables: T
8
+ includeBooleanTransform?: boolean
9
+ }
10
+
11
+ export function processTemplate<T extends object>(options: TemplateOptions<T>): string {
12
+ const {template, variables, includeBooleanTransform = false} = options
13
+ const ast = parse(template.trimStart(), {parser})
14
+
15
+ traverse(ast, {
16
+ StringLiteral: {
17
+ enter({node}) {
18
+ const value = node.value
19
+ if (!value.startsWith('%') || !value.endsWith('%')) {
20
+ return
21
+ }
22
+ const variableName = value.slice(1, -1) as keyof T
23
+ if (!(variableName in variables)) {
24
+ throw new Error(`Template variable '${value}' not defined`)
25
+ }
26
+ const newValue = variables[variableName]
27
+ /*
28
+ * although there are valid non-strings in our config,
29
+ * they're not in StringLiteral nodes, so assume undefined
30
+ */
31
+ node.value = typeof newValue === 'string' ? newValue : ''
32
+ },
33
+ },
34
+ ...(includeBooleanTransform && {
35
+ Identifier: {
36
+ enter(path) {
37
+ if (!path.node.name.startsWith('__BOOL__')) {
38
+ return
39
+ }
40
+ const variableName = path.node.name.replace(/^__BOOL__(.+?)__$/, '$1') as keyof T
41
+ if (!(variableName in variables)) {
42
+ throw new Error(`Template variable '${variableName.toString()}' not defined`)
43
+ }
44
+ const value = variables[variableName]
45
+ if (typeof value !== 'boolean') {
46
+ throw new Error(`Expected boolean value for '${variableName.toString()}'`)
47
+ }
48
+ path.replaceWith({type: 'BooleanLiteral', value})
49
+ },
50
+ },
51
+ }),
52
+ })
53
+
54
+ return print(ast, {quote: 'single'}).code
55
+ }
@@ -0,0 +1,31 @@
1
+ import {type ProjectTemplate} from '../initProject'
2
+
3
+ const coreAppTemplate: ProjectTemplate = {
4
+ dependencies: {
5
+ '@sanity/sdk': '^0.0.0-alpha',
6
+ '@sanity/sdk-react': '^0.0.0-alpha',
7
+ 'react': '^19',
8
+ 'react-dom': '^19',
9
+ },
10
+ devDependencies: {
11
+ /*
12
+ * this will be changed to eslint-config sanity,
13
+ * eslint.config generation will be a fast follow
14
+ */
15
+ '@sanity/eslint-config-studio': '^5.0.1',
16
+ '@types/react': '^18.0.25',
17
+ 'eslint': '^9.9.0',
18
+ 'prettier': '^3.0.2',
19
+ 'sanity': '^3',
20
+ 'typescript': '^5.1.6',
21
+ },
22
+ appLocation: './src/App.tsx',
23
+ scripts: {
24
+ // this will eventually run a concurrently process with another in-flight utility
25
+ dev: 'sanity app dev',
26
+ build: 'sanity app build',
27
+ start: 'sanity app start',
28
+ },
29
+ }
30
+
31
+ export default coreAppTemplate
@@ -1,6 +1,7 @@
1
1
  import {type ProjectTemplate} from '../initProject'
2
2
  import blog from './blog'
3
3
  import clean from './clean'
4
+ import coreAppTemplate from './coreApp'
4
5
  import getStartedTemplate from './getStarted'
5
6
  import moviedb from './moviedb'
6
7
  import quickstart from './quickstart'
@@ -10,6 +11,7 @@ import shopifyOnline from './shopifyOnline'
10
11
  const templates: Record<string, ProjectTemplate | undefined> = {
11
12
  blog,
12
13
  clean,
14
+ 'core-app': coreAppTemplate,
13
15
  'get-started': getStartedTemplate,
14
16
  moviedb,
15
17
  shopify,
package/src/types.ts CHANGED
@@ -24,6 +24,7 @@ export interface SanityModuleInternal {
24
24
  export interface PackageJson {
25
25
  name: string
26
26
  version: string
27
+ scripts?: Record<string, string>
27
28
 
28
29
  description?: string
29
30
  author?: string
@@ -344,6 +345,15 @@ export interface CliConfig {
344
345
  autoUpdates?: boolean
345
346
 
346
347
  studioHost?: string
348
+
349
+ /**
350
+ * Parameter used to configure other kinds of applications.
351
+ * Signals to `sanity` commands that this is not a studio.
352
+ * @internal
353
+ */
354
+ __experimental_coreAppConfiguration?: {
355
+ appLocation?: string
356
+ }
347
357
  }
348
358
 
349
359
  export type UserViteConfig =
@@ -0,0 +1,26 @@
1
+ import {createSanityInstance} from '@sanity/sdk'
2
+ import {SanityProvider} from '@sanity/sdk-react/context'
3
+
4
+ export function App() {
5
+
6
+ const sanityConfig = {
7
+ auth: {
8
+ authScope: 'global'
9
+ }
10
+ /*
11
+ * Apps can access several different projects!
12
+ * Add the below configuration if you want to connect to a specific project.
13
+ */
14
+ // projectId: 'my-project-id',
15
+ // dataset: 'my-dataset',
16
+ }
17
+
18
+ const sanityInstance = createSanityInstance(sanityConfig)
19
+ return (
20
+ <SanityProvider sanityInstance={sanityInstance}>
21
+ Hello world!
22
+ </SanityProvider>
23
+ )
24
+ }
25
+
26
+ export default App