@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/_chunks-cjs/cli.js +146 -82
- package/lib/_chunks-cjs/cli.js.map +1 -1
- package/lib/index.d.mts +10 -0
- package/lib/index.d.ts +10 -0
- package/package.json +7 -7
- package/src/actions/init-project/bootstrapLocalTemplate.ts +35 -20
- package/src/actions/init-project/createCliConfig.ts +5 -47
- package/src/actions/init-project/createCoreAppCliConfig.ts +26 -0
- package/src/actions/init-project/createPackageManifest.ts +1 -1
- package/src/actions/init-project/createStudioConfig.ts +5 -27
- package/src/actions/init-project/determineCoreAppTemplate.ts +13 -0
- package/src/actions/init-project/initProject.ts +41 -13
- package/src/actions/init-project/processTemplate.ts +55 -0
- package/src/actions/init-project/templates/coreApp.ts +31 -0
- package/src/actions/init-project/templates/index.ts +2 -0
- package/src/types.ts +11 -0
- package/templates/core-app/src/App.tsx +26 -0
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.
|
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.
|
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.
|
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.
|
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
|
129
|
-
"vitest": "^
|
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": "
|
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 =
|
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 =
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
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
|
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
|
-
|
29
|
-
|
30
|
-
|
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
|
+
}
|
@@ -1,6 +1,4 @@
|
|
1
|
-
import
|
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
|
-
|
51
|
-
|
52
|
-
|
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
|
-
//
|
275
|
-
const
|
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(
|
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(
|
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
|
1242
|
+
let orgId = flags.organization
|
1215
1243
|
if (unattended) {
|
1216
|
-
return
|
1244
|
+
return orgId || undefined
|
1217
1245
|
}
|
1218
1246
|
|
1219
|
-
const shouldPrompt = organizations.length > 0 && !
|
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
|
-
|
1273
|
+
orgId = chosenOrg
|
1246
1274
|
}
|
1247
|
-
} else if (
|
1248
|
-
debug(`User has defined organization flag explicitly (%s)`,
|
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
|
1281
|
+
return orgId || undefined
|
1254
1282
|
}
|
1255
1283
|
|
1256
|
-
async function hasProjectAttachGrant(
|
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/${
|
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
|