@sanity/cli 3.88.0 → 3.88.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli",
3
- "version": "3.88.0",
3
+ "version": "3.88.1",
4
4
  "description": "Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets",
5
5
  "keywords": [
6
6
  "sanity",
@@ -59,11 +59,11 @@
59
59
  "dependencies": {
60
60
  "@babel/traverse": "^7.23.5",
61
61
  "@sanity/client": "^7.1.0",
62
- "@sanity/codegen": "3.88.0",
63
- "@sanity/runtime-cli": "^3.0.0",
62
+ "@sanity/codegen": "3.88.1",
63
+ "@sanity/runtime-cli": "^6.1.1",
64
64
  "@sanity/telemetry": "^0.8.0",
65
65
  "@sanity/template-validator": "^2.4.3",
66
- "@sanity/util": "3.88.0",
66
+ "@sanity/util": "3.88.1",
67
67
  "chalk": "^4.1.2",
68
68
  "debug": "^4.3.4",
69
69
  "decompress": "^4.2.0",
@@ -77,13 +77,13 @@
77
77
  "validate-npm-package-name": "^3.0.0"
78
78
  },
79
79
  "devDependencies": {
80
- "@repo/package.config": "3.88.0",
81
- "@repo/test-config": "3.88.0",
80
+ "@repo/package.config": "3.88.1",
81
+ "@repo/test-config": "3.88.1",
82
82
  "@rexxars/gitconfiglocal": "^3.0.1",
83
83
  "@rollup/plugin-node-resolve": "^15.2.3",
84
84
  "@sanity/eslint-config-studio": "^4.0.0",
85
85
  "@sanity/generate-help-url": "^3.0.0",
86
- "@sanity/types": "3.88.0",
86
+ "@sanity/types": "3.88.1",
87
87
  "@types/babel__traverse": "^7.20.5",
88
88
  "@types/configstore": "^5.0.1",
89
89
  "@types/cpx": "^1.5.2",
@@ -135,5 +135,5 @@
135
135
  "engines": {
136
136
  "node": ">=18"
137
137
  },
138
- "gitHead": "0e6a13c8ff235c14612a8a0f6cf0cd227a96c275"
138
+ "gitHead": "26a4552965274b9d35f92b9d1191eb029cb913e8"
139
139
  }
@@ -2,79 +2,75 @@ import {type CliCommandDefinition} from '../../types'
2
2
 
3
3
  const helpText = `
4
4
  Arguments
5
- [type] Type of Resource to add (currently only 'function' is supported)
5
+ <type> Type of Resource to add (currently only 'function' is supported)
6
6
 
7
- Examples
8
- # Add a Function Resource
7
+ Options
8
+ --name <name> Name of the Resource
9
+ --fn-type <type> Type of Function Resource to add (e.g. document-publish)
10
+ --fn-lang, --lang <ts|js> Language of the Function Resource
11
+ --js, --javascript Use JavaScript for the Function Resource
12
+
13
+ Examples:
14
+ # Add a Function Resource (TypeScript by default)
9
15
  sanity blueprints add function
16
+
17
+ # Add a Function Resource with a specific name
18
+ sanity blueprints add function --name my-function
19
+
20
+ # Add a Function Resource with a specific type
21
+ sanity blueprints add function --name my-function --fn-type document-publish
22
+
23
+ # Add a Function Resource in JavaScript
24
+ sanity blueprints add function --name my-function --fn-type document-publish --js
10
25
  `
11
26
 
12
- const addBlueprintsCommand: CliCommandDefinition = {
27
+ export interface BlueprintsAddFlags {
28
+ 'name'?: string
29
+ 'fn-type'?: string
30
+ 'fn-lang'?: string
31
+ 'language'?: string
32
+ 'lang'?: string
33
+ 'js'?: boolean
34
+ 'javascript'?: boolean
35
+ }
36
+
37
+ const defaultFlags: BlueprintsAddFlags = {
38
+ //
39
+ }
40
+
41
+ const addBlueprintsCommand: CliCommandDefinition<BlueprintsAddFlags> = {
13
42
  name: 'add',
14
43
  group: 'blueprints',
15
44
  helpText,
16
- signature: '<type>',
45
+ signature:
46
+ '<type> [--name <name>] [--fn-type <document-publish>] [--fn-lang <ts|js>] [--javascript]',
17
47
  description: 'Add a Resource to a Blueprint',
18
- hideFromHelp: true,
48
+
19
49
  async action(args, context) {
20
- const {output, prompt} = context
21
- const {print} = output
50
+ const {output} = context
51
+ const flags = {...defaultFlags, ...args.extOptions}
22
52
 
23
53
  const [resourceType] = args.argsWithoutOptions
24
54
 
25
55
  if (!resourceType) {
26
- print('Resource type is required. Available types: function')
27
- return
28
- }
29
-
30
- const {blueprint: blueprintAction, resources: resourcesAction} = await import(
31
- '@sanity/runtime-cli/actions/blueprints'
32
- )
33
-
34
- const existingBlueprint = blueprintAction.findBlueprintFile()
35
- if (!existingBlueprint) {
36
- print('No blueprint file found. Run `sanity blueprints init` first.')
56
+ output.error('Resource type is required. Available types: function')
37
57
  return
38
58
  }
39
59
 
40
- if (resourceType === 'function') {
41
- const functionName = await prompt.single({
42
- type: 'input',
43
- message: 'Enter function name:',
44
- validate: (input: string) => input.length > 0 || 'Function name is required',
45
- })
46
-
47
- const functionType = await prompt.single({
48
- type: 'list',
49
- message: 'Choose function type:',
50
- choices: [
51
- {value: 'document-publish', name: 'Document Publish'},
52
- {value: 'document-create', name: 'Document Create (Available soon)', disabled: true},
53
- {value: 'document-delete', name: 'Document Delete (Available soon)', disabled: true},
54
- ],
55
- })
56
-
57
- const {filePath, resourceAdded, resource} = resourcesAction.createFunctionResource({
58
- name: functionName,
59
- type: functionType,
60
- displayName: functionName,
61
- })
62
-
63
- print(`\nCreated function: ${filePath}`)
64
-
65
- if (resourceAdded) {
66
- // added to blueprint.json
67
- print('Function Resource added to Blueprint')
68
- } else {
69
- // print the resource JSON for manual addition
70
- print('\nAdd this Function Resource to your Blueprint:')
71
- print(JSON.stringify(resource, null, 2))
72
- }
73
-
74
- return
75
- }
60
+ const {blueprintAddCore} = await import('@sanity/runtime-cli/cores/blueprints')
61
+ const {success, error} = await blueprintAddCore({
62
+ bin: 'sanity',
63
+ log: (msg) => output.print(msg),
64
+ args: {type: resourceType},
65
+ flags: {
66
+ 'name': flags.name,
67
+ 'fn-type': flags['fn-type'],
68
+ 'language': flags['fn-lang'] ?? flags.language ?? flags.lang,
69
+ 'javascript': flags.js || flags.javascript,
70
+ },
71
+ })
76
72
 
77
- print(`Unsupported resource type: ${resourceType}. Available types: function`)
73
+ if (!success) throw new Error(error)
78
74
  },
79
75
  }
80
76
 
@@ -5,7 +5,6 @@ const blueprintsGroup: CliCommandGroupDefinition = {
5
5
  signature: '[COMMAND]',
6
6
  isGroupRoot: true,
7
7
  description: 'Deploy and manage Sanity Blueprints and Stacks (IaC)',
8
- hideFromHelp: true,
9
8
  }
10
9
 
11
10
  export default blueprintsGroup
@@ -2,30 +2,51 @@ import {type CliCommandDefinition} from '../../types'
2
2
 
3
3
  const helpText = `
4
4
  Options
5
- --edit Edit the configuration
5
+ --edit, -e Edit the configuration
6
+ --test, -t Test the configuration
7
+ --project-id <id> Project ID to use
6
8
 
7
- Examples
9
+ Examples:
8
10
  # View current configuration
9
11
  sanity blueprints config
10
12
 
11
13
  # Edit configuration
12
14
  sanity blueprints config --edit
15
+
16
+ # Test configuration
17
+ sanity blueprints config --test
18
+
19
+ # Edit and test configuration
20
+ sanity blueprints config -et
13
21
  `
14
22
 
15
- const defaultFlags = {
16
- edit: false,
23
+ export interface BlueprintsConfigFlags {
24
+ 'test-config'?: boolean
25
+ 'test'?: boolean
26
+ 't'?: boolean
27
+ 'edit'?: boolean
28
+ 'e'?: boolean
29
+ 'project-id'?: string
30
+ 'projectId'?: string
31
+ 'project'?: string
32
+ 'stack-id'?: string
33
+ 'stackId'?: string
34
+ 'stack'?: string
35
+ }
36
+
37
+ const defaultFlags: BlueprintsConfigFlags = {
38
+ //
17
39
  }
18
40
 
19
- const configBlueprintsCommand: CliCommandDefinition = {
41
+ const configBlueprintsCommand: CliCommandDefinition<BlueprintsConfigFlags> = {
20
42
  name: 'config',
21
43
  group: 'blueprints',
22
44
  helpText,
23
- signature: '[--edit]',
45
+ signature: '[--edit] [-e] [--test] [-t] [--project-id <id>]',
24
46
  description: 'View or edit local Blueprints configuration',
25
- hideFromHelp: true,
47
+
26
48
  async action(args, context) {
27
- const {apiClient, output, prompt} = context
28
- const {print} = output
49
+ const {apiClient, output} = context
29
50
  const flags = {...defaultFlags, ...args.extOptions}
30
51
 
31
52
  const client = apiClient({
@@ -33,79 +54,34 @@ const configBlueprintsCommand: CliCommandDefinition = {
33
54
  requireProject: false,
34
55
  })
35
56
  const {token} = client.config()
36
- const {
37
- blueprint: blueprintAction,
38
- projects: projectsAction,
39
- stacks: stacksAction,
40
- } = await import('@sanity/runtime-cli/actions/blueprints')
41
-
42
- const config = blueprintAction.readConfigFile()
43
- if (!config) {
44
- print('No configuration found. Run `sanity blueprints init` first.')
45
- return
46
- }
47
57
 
48
- print('\nCurrent configuration:')
49
- print(JSON.stringify(config, null, 2))
50
-
51
- if (!flags.edit) {
52
- return
53
- }
58
+ if (!token) throw new Error('No API token found. Please run `sanity login`.')
54
59
 
55
- if (!token) {
56
- print('No API token found. Please run `sanity login` first.')
57
- return
58
- }
60
+ const {blueprintConfigCore} = await import('@sanity/runtime-cli/cores/blueprints')
61
+ const {getBlueprintAndStack} = await import('@sanity/runtime-cli/actions/blueprints')
62
+ const {display} = await import('@sanity/runtime-cli/utils')
59
63
 
60
- const {ok, projects, error} = await projectsAction.listProjects({token})
61
- if (!ok) {
62
- print(error)
63
- return
64
- }
64
+ const {localBlueprint, issues} = await getBlueprintAndStack({token})
65
65
 
66
- if (!projects || projects.length === 0) {
67
- print('No Projects found. Please create a Project in Sanity.io first.')
68
- return
66
+ if (issues) {
67
+ // print issues and continue
68
+ output.print(display.errors.presentBlueprintIssues(issues))
69
69
  }
70
70
 
71
- const projectChoices = projects.map(({displayName, id}) => ({
72
- value: id,
73
- name: `${displayName} <${id}>`,
74
- }))
75
-
76
- const projectId = await prompt.single({
77
- type: 'list',
78
- message: 'Select your Sanity Project:',
79
- choices: projectChoices,
80
- default: config.projectId,
71
+ const {success, error} = await blueprintConfigCore({
72
+ bin: 'sanity',
73
+ log: (message) => output.print(message),
74
+ blueprint: localBlueprint,
75
+ token,
76
+ flags: {
77
+ 'project-id': flags['project-id'] ?? flags.projectId ?? flags.project,
78
+ 'stack-id': flags['stack-id'] ?? flags.stackId ?? flags.stack,
79
+ 'test-config': flags['test-config'] ?? flags.test ?? flags.t,
80
+ 'edit': flags.edit ?? flags.e,
81
+ },
81
82
  })
82
83
 
83
- const auth = {token, projectId}
84
-
85
- // get stacks for selected project
86
- const {ok: stacksOk, stacks, error: stacksError} = await stacksAction.listStacks(auth)
87
- if (!stacksOk) {
88
- print(stacksError)
89
- return
90
- }
91
-
92
- let stackId
93
- if (stacks && stacks.length > 0) {
94
- const stackChoices = stacks.map(({name, id}) => ({
95
- value: id,
96
- name: `${name} <${id}>`,
97
- }))
98
-
99
- stackId = await prompt.single({
100
- type: 'list',
101
- message: 'Select a Stack:',
102
- choices: stackChoices,
103
- default: config.stackId,
104
- })
105
- }
106
-
107
- blueprintAction.writeConfigFile({projectId, stackId})
108
- print('\nConfiguration updated successfully.')
84
+ if (!success) throw new Error(error)
109
85
  },
110
86
  }
111
87
 
@@ -1,163 +1,71 @@
1
1
  import {type CliCommandDefinition} from '../../types'
2
2
 
3
3
  const helpText = `
4
- Examples
4
+ Options
5
+ --no-wait Do not wait for deployment to complete
6
+
7
+ Examples:
5
8
  # Deploy the current blueprint
6
9
  sanity blueprints deploy
10
+
11
+ # Deploy the current blueprint without waiting for completion
12
+ sanity blueprints deploy --no-wait
7
13
  `
8
14
 
9
- const deployBlueprintsCommand: CliCommandDefinition = {
15
+ export interface BlueprintsDeployFlags {
16
+ 'no-wait'?: boolean
17
+ }
18
+
19
+ const defaultFlags: BlueprintsDeployFlags = {
20
+ //
21
+ }
22
+
23
+ const deployBlueprintsCommand: CliCommandDefinition<BlueprintsDeployFlags> = {
10
24
  name: 'deploy',
11
25
  group: 'blueprints',
12
26
  helpText,
13
- signature: '',
27
+ signature: '[--no-wait]',
14
28
  description: 'Deploy a Blueprint to create or update a Stack',
15
- hideFromHelp: true,
16
- /* eslint-disable-next-line complexity, max-statements */
29
+
17
30
  async action(args, context) {
18
- const {apiClient, output, prompt} = context
19
- const {print} = output
31
+ const {apiClient, output} = context
32
+ const flags = {...defaultFlags, ...args.extOptions}
20
33
 
21
34
  const client = apiClient({
22
35
  requireUser: true,
23
36
  requireProject: false,
24
37
  })
25
38
  const {token} = client.config()
26
- const {
27
- blueprint: blueprintAction,
28
- stacks: stacksAction,
29
- assets: assetsAction,
30
- } = await import('@sanity/runtime-cli/actions/blueprints')
31
- const {display} = await import('@sanity/runtime-cli/utils')
32
-
33
- if (!token) {
34
- print('No API token found. Please run `sanity login` first.')
35
- return
36
- }
37
-
38
- let blueprint = null
39
- try {
40
- blueprint = await blueprintAction.readBlueprintOnDisk({getStack: true, token})
41
- } catch (error) {
42
- print('Unable to read Blueprint manifest file. Run `sanity blueprints init`')
43
- return
44
- }
45
-
46
- if (!blueprint) {
47
- print('Unable to read Blueprint manifest file. Run `sanity blueprints init`')
48
- return
49
- }
50
-
51
- const {
52
- errors,
53
- projectId: configuredProjectId,
54
- stackId,
55
- parsedBlueprint,
56
- deployedStack,
57
- } = blueprint
58
-
59
- if (errors && errors.length > 0) {
60
- print(errors)
61
- return
62
- }
63
-
64
- if (stackId && !deployedStack) {
65
- print('Stack specified in config, but deployed Stack not found.')
66
- return
67
- }
68
-
69
- const resources = parsedBlueprint.resources || []
39
+ if (!token) throw new Error('No API token found. Please run `sanity login`.')
70
40
 
71
- let projectId = configuredProjectId
72
- if (!projectId) {
73
- print('No Sanity Project context found in Blueprint configuration.')
74
-
75
- const maybeProjectId = await prompt.single({
76
- type: 'input',
77
- message: 'Enter Sanity Project ID:',
78
- })
41
+ const {blueprintDeployCore} = await import('@sanity/runtime-cli/cores/blueprints')
42
+ const {getBlueprintAndStack} = await import('@sanity/runtime-cli/actions/blueprints')
43
+ const {display} = await import('@sanity/runtime-cli/utils')
79
44
 
80
- projectId = maybeProjectId
81
- }
45
+ const {localBlueprint, deployedStack, issues} = await getBlueprintAndStack({token})
82
46
 
83
- if (!projectId) {
84
- print('Sanity Project context is required')
85
- print('To configure this Blueprint, run `sanity blueprints config`')
86
- return
47
+ if (issues) {
48
+ output.print(display.errors.presentBlueprintIssues(issues))
49
+ throw new Error('Unable to parse Blueprint file.')
87
50
  }
88
51
 
52
+ const {projectId, stackId} = localBlueprint
89
53
  const auth = {token, projectId}
90
54
 
91
- let name = deployedStack?.name
92
- if (!name) {
93
- const stackName = await prompt.single({
94
- type: 'input',
95
- message: 'Enter stack name:',
96
- validate: (input) => input.length > 0 || 'Stack name is required',
97
- })
98
-
99
- name = stackName
100
- }
101
-
102
- if (!name) {
103
- print('Stack name is required')
104
- return
105
- }
106
-
107
- const validResources = resources?.filter((r) => r.type)
108
- const functionResources = validResources?.filter((r) => r.type.startsWith('sanity.function.'))
109
-
110
- if (functionResources?.length) {
111
- for (const resource of functionResources) {
112
- print(`Processing ${resource.name}...`)
113
- const result = await assetsAction.stashAsset({resource, auth})
114
-
115
- if (result.success && result.assetId) {
116
- const src = resource.src
117
- resource.src = result.assetId // ! this will change! for now, the API expects the assetId
118
- const {yellow} = display.colors
119
- print(`${resource.name} <${yellow(result.assetId)}>`)
120
- print(` Source: ${src}`)
121
- } else {
122
- print(` Error: ${result.error}`)
123
- throw new Error(`Failed to process ${resource.name}`)
124
- }
125
- }
126
- }
127
-
128
- const stackPayload = {
129
- name,
55
+ const {success, error} = await blueprintDeployCore({
56
+ bin: 'sanity',
57
+ log: (message) => output.print(message),
58
+ auth,
130
59
  projectId,
131
- document: {resources: validResources},
132
- }
133
-
134
- print('Deploying stack...')
135
-
136
- const {
137
- ok: deployOk,
138
- stack,
139
- error: deployError,
140
- } = deployedStack
141
- ? await stacksAction.updateStack({stackId: deployedStack.id, stackPayload, auth})
142
- : await stacksAction.createStack({stackPayload, auth})
143
-
144
- if (deployOk) {
145
- const {green, bold, yellow} = display.colors
146
- print(
147
- `${green('Success!')} Stack "${bold(stack.name)}" ${deployedStack ? 'updated' : 'created'} <${yellow(stack.id)}>`,
148
- )
149
-
150
- blueprintAction.writeConfigFile({
151
- projectId,
152
- stackId: stack.id,
153
- })
60
+ stackId,
61
+ deployedStack,
62
+ blueprint: localBlueprint,
63
+ flags: {
64
+ 'no-wait': flags['no-wait'],
65
+ },
66
+ })
154
67
 
155
- print('\nUse `sanity blueprints info` to check deployment status')
156
- } else {
157
- const {red} = display.colors
158
- print(`${red('Failed')} to ${deployedStack ? 'update' : 'create'} stack`)
159
- print(`Error: ${deployError || JSON.stringify(stack, null, 2) || 'Unknown error'}`)
160
- }
68
+ if (!success) throw new Error(error)
161
69
  },
162
70
  }
163
71
 
@@ -0,0 +1,76 @@
1
+ import {type CliCommandDefinition} from '../../types'
2
+
3
+ const helpText = `
4
+ Options
5
+ --force, -f Force destroy without confirmation
6
+ --no-wait Do not wait for destroy to complete
7
+
8
+ Examples:
9
+ # Destroy the current deployment
10
+ sanity blueprints destroy
11
+
12
+ # Force destroy without confirmation
13
+ sanity blueprints destroy --force
14
+
15
+ # Destroy without waiting for completion
16
+ sanity blueprints destroy --no-wait
17
+ `
18
+
19
+ export interface BlueprintsDestroyFlags {
20
+ 'force'?: boolean
21
+ 'f'?: boolean
22
+ 'project-id'?: string
23
+ 'projectId'?: string
24
+ 'project'?: string
25
+ 'stack-id'?: string
26
+ 'stackId'?: string
27
+ 'stack'?: string
28
+ 'no-wait'?: boolean
29
+ }
30
+
31
+ const defaultFlags: BlueprintsDestroyFlags = {
32
+ //
33
+ }
34
+
35
+ const destroyBlueprintsCommand: CliCommandDefinition<BlueprintsDestroyFlags> = {
36
+ name: 'destroy',
37
+ group: 'blueprints',
38
+ helpText,
39
+ signature: '[--force] [-f] [--no-wait]',
40
+ description: 'Destroy a Blueprint deployment',
41
+ hideFromHelp: true,
42
+
43
+ async action(args, context) {
44
+ const {apiClient, output} = context
45
+ const flags = {...defaultFlags, ...args.extOptions}
46
+
47
+ const client = apiClient({
48
+ requireUser: true,
49
+ requireProject: false,
50
+ })
51
+ const {token} = client.config()
52
+ if (!token) throw new Error('No API token found. Please run `sanity login`.')
53
+
54
+ const {blueprintDestroyCore} = await import('@sanity/runtime-cli/cores/blueprints')
55
+ const {getBlueprintAndStack} = await import('@sanity/runtime-cli/actions/blueprints')
56
+
57
+ const {localBlueprint} = await getBlueprintAndStack({token})
58
+
59
+ const {success, error} = await blueprintDestroyCore({
60
+ bin: 'sanity',
61
+ log: (message) => output.print(message),
62
+ token,
63
+ blueprint: localBlueprint,
64
+ flags: {
65
+ 'no-wait': flags['no-wait'],
66
+ 'force': flags.force ?? flags.f,
67
+ 'project-id': flags['project-id'] ?? flags.projectId ?? flags.project,
68
+ 'stack-id': flags['stack-id'] ?? flags.stackId ?? flags.stack,
69
+ },
70
+ })
71
+
72
+ if (!success) throw new Error(error)
73
+ },
74
+ }
75
+
76
+ export default destroyBlueprintsCommand