@sanity/cli 3.74.1 → 3.74.2-canary.67

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
@@ -14,6 +14,7 @@ export declare type CliApiClient = (options?: ClientRequirements) => SanityClien
14
14
 
15
15
  export declare interface CliApiConfig {
16
16
  projectId?: string
17
+ organizationId?: string
17
18
  dataset?: string
18
19
  }
19
20
 
@@ -114,6 +115,14 @@ export declare interface CliConfig {
114
115
  vite?: UserViteConfig
115
116
  autoUpdates?: boolean
116
117
  studioHost?: string
118
+ /**
119
+ * Parameter used to configure other kinds of applications.
120
+ * Signals to `sanity` commands that this is not a studio.
121
+ * @internal
122
+ */
123
+ __experimental_coreAppConfiguration?: {
124
+ appLocation?: string
125
+ }
117
126
  }
118
127
 
119
128
  declare type CliConfigResult =
@@ -357,6 +366,7 @@ export declare function loadEnv(
357
366
  export declare interface PackageJson {
358
367
  name: string
359
368
  version: string
369
+ scripts?: Record<string, string>
360
370
  description?: string
361
371
  author?: string
362
372
  license?: string
package/lib/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export declare type CliApiClient = (options?: ClientRequirements) => SanityClien
14
14
 
15
15
  export declare interface CliApiConfig {
16
16
  projectId?: string
17
+ organizationId?: string
17
18
  dataset?: string
18
19
  }
19
20
 
@@ -114,6 +115,14 @@ export declare interface CliConfig {
114
115
  vite?: UserViteConfig
115
116
  autoUpdates?: boolean
116
117
  studioHost?: string
118
+ /**
119
+ * Parameter used to configure other kinds of applications.
120
+ * Signals to `sanity` commands that this is not a studio.
121
+ * @internal
122
+ */
123
+ __experimental_coreAppConfiguration?: {
124
+ appLocation?: string
125
+ }
117
126
  }
118
127
 
119
128
  declare type CliConfigResult =
@@ -357,6 +366,7 @@ export declare function loadEnv(
357
366
  export declare interface PackageJson {
358
367
  name: string
359
368
  version: string
369
+ scripts?: Record<string, string>
360
370
  description?: string
361
371
  author?: string
362
372
  license?: string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli",
3
- "version": "3.74.1",
3
+ "version": "3.74.2-canary.67+a9a66e73d5",
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.1",
61
+ "@sanity/codegen": "3.74.2-canary.67+a9a66e73d5",
62
62
  "@sanity/telemetry": "^0.7.7",
63
63
  "@sanity/template-validator": "^2.4.0",
64
- "@sanity/util": "3.74.1",
64
+ "@sanity/util": "3.74.2-canary.67+a9a66e73d5",
65
65
  "chalk": "^4.1.2",
66
66
  "debug": "^4.3.4",
67
67
  "decompress": "^4.2.0",
@@ -81,7 +81,7 @@
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.1",
84
+ "@sanity/types": "3.74.2-canary.67+a9a66e73d5",
85
85
  "@types/babel__traverse": "^7.20.5",
86
86
  "@types/configstore": "^5.0.1",
87
87
  "@types/cpx": "^1.5.2",
@@ -125,13 +125,13 @@
125
125
  "semver": "^7.3.5",
126
126
  "semver-compare": "^1.0.0",
127
127
  "tar": "^6.1.11",
128
- "vite": "^6.0.11",
129
- "vitest": "^2.1.9",
128
+ "vite": "^6.1.0",
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": "51a67224fe7fd4f3efced0fcd833d47cb617f3c2"
136
+ "gitHead": "a9a66e73d50a681d71e210b8747c50fde8de637b"
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,44 @@ 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({
134
+ appLocation: template.appLocation!,
135
+ organizationId: variables.organizationId,
136
+ })
137
+ : createCliConfig({
138
+ projectId: variables.projectId,
139
+ dataset: variables.dataset,
140
+ autoUpdates: variables.autoUpdates,
141
+ })
133
142
 
134
143
  // Write non-template files to disc
135
144
  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
- ])
145
+ await Promise.all(
146
+ [
147
+ ...[
148
+ isCoreAppTemplate
149
+ ? Promise.resolve(null)
150
+ : writeFileIfNotExists(`sanity.config.${codeExt}`, studioConfig),
151
+ ],
152
+ writeFileIfNotExists(`sanity.cli.${codeExt}`, cliConfig),
153
+ writeFileIfNotExists('package.json', packageManifest),
154
+ writeFileIfNotExists(
155
+ 'eslint.config.mjs',
156
+ `import studio from '@sanity/eslint-config-studio'\n\nexport default [...studio]\n`,
157
+ ),
158
+ ].filter(Boolean),
159
+ )
145
160
 
146
161
  debug('Updating initial template metadata')
147
162
  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,26 @@
1
+ import {processTemplate} from './processTemplate'
2
+
3
+ const defaultCoreAppTemplate = `
4
+ import {defineCliConfig} from 'sanity/cli'
5
+
6
+ export default defineCliConfig({
7
+ api: {
8
+ organizationId: '%organizationId%'
9
+ },
10
+ __experimental_coreAppConfiguration: {
11
+ appLocation: '%appLocation%'
12
+ },
13
+ })
14
+ `
15
+
16
+ export interface GenerateCliConfigOptions {
17
+ organizationId?: string
18
+ appLocation: string
19
+ }
20
+
21
+ export function createCoreAppCliConfig(options: GenerateCliConfigOptions): string {
22
+ return processTemplate({
23
+ template: defaultCoreAppTemplate,
24
+ variables: options,
25
+ })
26
+ }
@@ -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'
@@ -38,6 +36,7 @@ export interface GenerateConfigOptions {
38
36
  projectName?: string
39
37
  sourceName?: string
40
38
  sourceTitle?: string
39
+ organizationId?: string
41
40
  }
42
41
  }
43
42
 
@@ -47,29 +46,8 @@ export function createStudioConfig(options: GenerateConfigOptions): string {
47
46
  return options.template(variables).trimStart()
48
47
  }
49
48
 
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
- },
49
+ return processTemplate({
50
+ template: options.template || defaultTemplate,
51
+ variables,
72
52
  })
73
-
74
- return print(ast, {quote: 'single'}).code
75
53
  }
@@ -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,8 +274,12 @@ export default async function initSanity(
271
274
  print('')
272
275
 
273
276
  const flags = await prepareFlags()
274
- // We're authenticated, now lets select or create a project
275
- const {projectId, displayName, isFirstProject, datasetName, schemaUrl} = await getProjectDetails()
277
+ // skip project / dataset prompting
278
+ const isCoreAppTemplate = cliFlags.template ? determineCoreAppTemplate(cliFlags.template) : false // Default to false
279
+
280
+ // We're authenticated, now lets select or create a project (for studios) or org (for core apps)
281
+ const {projectId, displayName, isFirstProject, datasetName, schemaUrl, organizationId} =
282
+ await getProjectDetails()
276
283
 
277
284
  const sluggedName = deburr(displayName.toLowerCase())
278
285
  .replace(/\s+/g, '-')
@@ -655,11 +662,15 @@ export default async function initSanity(
655
662
  const isCurrentDir = outputPath === process.cwd()
656
663
  if (isCurrentDir) {
657
664
  print(`\n${chalk.green('Success!')} Now, use this command to continue:\n`)
658
- print(`${chalk.cyan(devCommand)} - to run Sanity Studio\n`)
665
+ print(
666
+ `${chalk.cyan(devCommand)} - to run ${isCoreAppTemplate ? 'your Sanity application' : 'Sanity Studio'}\n`,
667
+ )
659
668
  } else {
660
669
  print(`\n${chalk.green('Success!')} Now, use these commands to continue:\n`)
661
670
  print(`First: ${chalk.cyan(`cd ${outputPath}`)} - to enter project’s directory`)
662
- print(`Then: ${chalk.cyan(devCommand)} - to run Sanity Studio\n`)
671
+ print(
672
+ `Then: ${chalk.cyan(devCommand)} -to run ${isCoreAppTemplate ? 'your Sanity application' : 'Sanity Studio'}\n`,
673
+ )
663
674
  }
664
675
 
665
676
  print(`Other helpful commands`)
@@ -705,6 +716,7 @@ export default async function initSanity(
705
716
  displayName: string
706
717
  isFirstProject: boolean
707
718
  schemaUrl?: string
719
+ organizationId?: string
708
720
  }> {
709
721
  // If we're doing a quickstart, we don't need to prompt for project details
710
722
  if (flags.quickstart) {
@@ -720,6 +732,21 @@ export default async function initSanity(
720
732
  return data
721
733
  }
722
734
 
735
+ if (isCoreAppTemplate) {
736
+ const client = apiClient({requireUser: true, requireProject: false})
737
+ const organizations = await client.request({uri: '/organizations'})
738
+
739
+ const coreAppOrganizationId = await getOrganizationId(organizations)
740
+
741
+ return {
742
+ projectId: '',
743
+ displayName: '',
744
+ datasetName: '',
745
+ isFirstProject: false,
746
+ organizationId: coreAppOrganizationId,
747
+ }
748
+ }
749
+
723
750
  debug('Prompting user to select or create a project')
724
751
  const project = await getOrCreateProject()
725
752
  debug(`Project with name ${project.displayName} selected`)
@@ -1072,6 +1099,7 @@ export default async function initSanity(
1072
1099
  dataset: datasetName,
1073
1100
  projectId,
1074
1101
  projectName: displayName || answers.projectName,
1102
+ organizationId,
1075
1103
  }
1076
1104
 
1077
1105
  if (remoteTemplateInfo) {
@@ -1211,12 +1239,12 @@ export default async function initSanity(
1211
1239
  }
1212
1240
 
1213
1241
  async function getOrganizationId(organizations: ProjectOrganization[]) {
1214
- let organizationId = flags.organization
1242
+ let orgId = flags.organization
1215
1243
  if (unattended) {
1216
- return organizationId || undefined
1244
+ return orgId || undefined
1217
1245
  }
1218
1246
 
1219
- const shouldPrompt = organizations.length > 0 && !organizationId
1247
+ const shouldPrompt = organizations.length > 0 && !orgId
1220
1248
  if (shouldPrompt) {
1221
1249
  debug(`User has ${organizations.length} organization(s), checking attach access`)
1222
1250
  const withGrant = await getOrganizationsWithAttachGrant(organizations)
@@ -1242,18 +1270,18 @@ export default async function initSanity(
1242
1270
  })
1243
1271
 
1244
1272
  if (chosenOrg && chosenOrg !== 'none') {
1245
- organizationId = chosenOrg
1273
+ orgId = chosenOrg
1246
1274
  }
1247
- } else if (organizationId) {
1248
- debug(`User has defined organization flag explicitly (%s)`, organizationId)
1275
+ } else if (orgId) {
1276
+ debug(`User has defined organization flag explicitly (%s)`, orgId)
1249
1277
  } else if (organizations.length === 0) {
1250
1278
  debug('User has no organizations, skipping selection prompt')
1251
1279
  }
1252
1280
 
1253
- return organizationId || undefined
1281
+ return orgId || undefined
1254
1282
  }
1255
1283
 
1256
- async function hasProjectAttachGrant(organizationId: string) {
1284
+ async function hasProjectAttachGrant(orgId: string) {
1257
1285
  const requiredGrantGroup = 'sanity.organization.projects'
1258
1286
  const requiredGrant = 'attach'
1259
1287
 
@@ -1261,7 +1289,7 @@ export default async function initSanity(
1261
1289
  .clone()
1262
1290
  .config({apiVersion: 'v2021-06-07'})
1263
1291
 
1264
- const grants = await client.request({uri: `organizations/${organizationId}/grants`})
1292
+ const grants = await client.request({uri: `organizations/${orgId}/grants`})
1265
1293
  const group: {grants: {name: string}[]}[] = grants[requiredGrantGroup] || []
1266
1294
  return group.some(
1267
1295
  (resource) =>
@@ -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
@@ -181,6 +182,7 @@ export type CliStubbedYarn = (args: string[], options?: CliYarnOptions) => Promi
181
182
 
182
183
  export interface CliApiConfig {
183
184
  projectId?: string
185
+ organizationId?: string
184
186
  dataset?: string
185
187
  }
186
188
 
@@ -344,6 +346,15 @@ export interface CliConfig {
344
346
  autoUpdates?: boolean
345
347
 
346
348
  studioHost?: string
349
+
350
+ /**
351
+ * Parameter used to configure other kinds of applications.
352
+ * Signals to `sanity` commands that this is not a studio.
353
+ * @internal
354
+ */
355
+ __experimental_coreAppConfiguration?: {
356
+ appLocation?: string
357
+ }
347
358
  }
348
359
 
349
360
  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