@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.
@@ -1,48 +1,47 @@
1
- import {type types} from '@sanity/runtime-cli/utils'
2
-
3
1
  import {type CliCommandDefinition} from '../../types'
4
2
 
5
- type StackFunctionResource = types.StackFunctionResource
6
-
7
3
  const helpText = `
8
- Arguments
9
- [add] Add or update an environment variable
10
- [remove] Remove an environment variable
4
+ Commands
5
+ add Add or update an environment variable
6
+ list List the environment variables
7
+ remove Remove an environment variable
11
8
 
12
- Options
13
- --name <name> The name of the function
14
- --key <key> The name of the environment variable
15
- --value <value> The value of the environment variable
9
+ Arguments
10
+ <name> The name of the function
11
+ <key> The name of the environment variable
12
+ <value> The value of the environment variable
16
13
 
17
14
  Examples
18
15
  # Add or update an environment variable
19
- sanity functions env add --name echo --key API_URL --value https://api.example.com/
16
+ sanity functions env add echo API_URL https://api.example.com/
20
17
 
21
18
  # Remove an environment variable
22
- sanity functions env remove --name echo --key API_URL
23
- `
19
+ sanity functions env remove echo API_URL
24
20
 
25
- const defaultFlags = {
26
- name: '',
27
- key: '',
28
- value: '',
29
- }
21
+ # List environment variables
22
+ sanity functions env list echo
23
+ `
30
24
 
31
25
  const envFunctionsCommand: CliCommandDefinition = {
32
26
  name: 'env',
33
27
  group: 'functions',
34
28
  helpText,
35
- signature: '',
36
- description: 'Add or remove an environment variable for a Sanity function',
37
- hideFromHelp: true,
29
+ signature: '<add|list|remove> <name> [key] [value]',
30
+ description:
31
+ 'Add or remove an environment variable or list environment variables for a Sanity function',
38
32
  async action(args, context) {
39
33
  const {apiClient, output} = context
40
34
  const {print} = output
41
- const [subCommand] = args.argsWithoutOptions
42
- const flags = {...defaultFlags, ...args.extOptions}
35
+ const [subCommand, name, key, value] = args.argsWithoutOptions
36
+
37
+ if (!subCommand || !['add', 'list', 'remove'].includes(subCommand)) {
38
+ throw new Error('You must specify if you want to list, add or remove')
39
+ }
43
40
 
44
- if (!subCommand || !['add', 'remove'].includes(subCommand)) {
45
- throw new Error('You must specify if you wish to add or remove an environment variable')
41
+ if (subCommand === 'add' && (!key || !value)) {
42
+ throw new Error('You must specify the name, key and value arguments')
43
+ } else if (subCommand === 'remove' && !key) {
44
+ throw new Error('You must specify the name and key arguments')
46
45
  }
47
46
 
48
47
  const client = apiClient({
@@ -50,19 +49,18 @@ const envFunctionsCommand: CliCommandDefinition = {
50
49
  requireProject: false,
51
50
  })
52
51
 
53
- if (flags.name === '') {
54
- throw new Error('You must provide a function name via the --name flag')
52
+ if (name === '') {
53
+ throw new Error('You must provide a function name as the first argument')
55
54
  }
56
55
 
57
56
  const token = client.config().token
58
- const {env} = await import('@sanity/runtime-cli/actions/functions')
59
- const {blueprint} = await import('@sanity/runtime-cli/actions/blueprints')
57
+ if (!token) throw new Error('No API token found. Please run `sanity login`.')
58
+
59
+ const {env: envAction} = await import('@sanity/runtime-cli/actions/functions')
60
+ const {blueprint, getBlueprintAndStack} = await import('@sanity/runtime-cli/actions/blueprints')
60
61
  const {findFunction} = await import('@sanity/runtime-cli/utils')
61
62
 
62
- const {deployedStack} = await blueprint.readBlueprintOnDisk({
63
- getStack: true,
64
- token,
65
- })
63
+ const {deployedStack} = await getBlueprintAndStack({token})
66
64
 
67
65
  if (!deployedStack) {
68
66
  throw new Error('Stack not found')
@@ -71,34 +69,45 @@ const envFunctionsCommand: CliCommandDefinition = {
71
69
  const blueprintConfig = blueprint.readConfigFile()
72
70
  const projectId = blueprintConfig?.projectId
73
71
 
74
- const {externalId} = findFunction.findFunctionByName(
75
- deployedStack,
76
- flags.name,
77
- ) as StackFunctionResource
72
+ const {externalId} = findFunction.findFunctionByName(deployedStack, name)
78
73
 
79
74
  if (token && projectId) {
80
75
  if (subCommand === 'add') {
81
- print(`Updating "${flags.key}" environment variable in "${flags.name}"`)
82
- const result = await env.update.update(externalId, flags.key, flags.value, {
76
+ print(`Updating "${key}" environment variable in "${name}"`)
77
+ const result = await envAction.update(externalId, key, value, {
83
78
  token,
84
79
  projectId,
85
80
  })
86
81
  if (result.ok) {
87
- print(`Update of ${flags.key} succeeded`)
82
+ print(`Update of "${key}" succeeded`)
88
83
  } else {
89
- print(`Failed to update ${flags.key}`)
84
+ print(`Failed to update "${key}"`)
90
85
  print(`Error: ${result.error || 'Unknown error'}`)
91
86
  }
92
87
  } else if (subCommand === 'remove') {
93
- print(`Removing "${flags.key}" environment variable in "${flags.name}"`)
94
- const result = await env.remove.remove(externalId, flags.key, {
88
+ print(`Removing "${key}" environment variable in "${name}"`)
89
+ const result = await envAction.remove(externalId, key, {
95
90
  token,
96
91
  projectId,
97
92
  })
98
93
  if (result.ok) {
99
- print(`Remove of ${flags.key} succeeded`)
94
+ print(`Removal of "${key}" succeeded`)
95
+ } else {
96
+ print(`Failed to remove "${key}"`)
97
+ print(`Error: ${result.error || 'Unknown error'}`)
98
+ }
99
+ } else if (subCommand === 'list') {
100
+ print(`Environment variables in "${name}"`)
101
+ const result = await envAction.list(externalId, {
102
+ token,
103
+ projectId,
104
+ })
105
+ if (result.ok && Array.isArray(result.envvars)) {
106
+ for (const envVarKey of result.envvars) {
107
+ print(envVarKey)
108
+ }
100
109
  } else {
101
- print(`Failed to remove ${flags.key}`)
110
+ print(`Failed to list environment variables in "${key}"`)
102
111
  print(`Error: ${result.error || 'Unknown error'}`)
103
112
  }
104
113
  }
@@ -4,8 +4,7 @@ const functionsGroup: CliCommandGroupDefinition = {
4
4
  name: 'functions',
5
5
  signature: '[COMMAND]',
6
6
  isGroupRoot: true,
7
- description: 'Test Sanity Functions locally and retrieve logs',
8
- hideFromHelp: true,
7
+ description: 'Test Sanity Functions locally, update environment variables and retrieve logs',
9
8
  }
10
9
 
11
10
  export default functionsGroup
@@ -1,44 +1,49 @@
1
- import {type types} from '@sanity/runtime-cli/utils'
1
+ import chalk from 'chalk'
2
+ import inquirer from 'inquirer'
2
3
 
3
4
  import {type CliCommandDefinition} from '../../types'
4
5
 
5
- type StackFunctionResource = types.StackFunctionResource
6
-
7
6
  const helpText = `
7
+ Arguments
8
+ <name> The name of the Function to retrieve logs for
9
+
8
10
  Options
9
- --name <name> The name of the function to retrieve logs for
10
11
  --limit <limit> The number of log entries to retrieve [default 50]
11
12
  --json If set return json
12
13
  --utc Use UTC dates in logs
13
14
 
14
15
  Examples
15
- # Retrieve logs for Sanity Function abcd1234
16
- sanity functions logs --name echo
16
+ # Retrieve logs for Sanity Function
17
+ sanity functions logs echo
17
18
 
18
- # Retrieve the last two log entries for Sanity Function abcd1234
19
- sanity functions logs --name echo --limit 2
19
+ # Retrieve the last two log entries for Sanity Function
20
+ sanity functions logs echo --limit 2
20
21
 
21
- # Retrieve logs for Sanity Function abcd1234 in json format
22
+ # Retrieve logs for Sanity Function in json format
22
23
  sanity functions logs --name echo --json
24
+
25
+ # Delete all logs for Sanity Function
26
+ sanity functions logs --name echo --delete
23
27
  `
24
28
 
25
29
  const defaultFlags = {
26
- name: '',
27
30
  limit: 50,
28
31
  json: false,
29
32
  utc: false,
33
+ delete: false,
34
+ force: false,
30
35
  }
31
36
 
32
37
  const logsFunctionsCommand: CliCommandDefinition = {
33
38
  name: 'logs',
34
39
  group: 'functions',
35
40
  helpText,
36
- signature: '',
37
- description: 'Retrieve logs for a Sanity Function',
38
- hideFromHelp: true,
41
+ signature: '<name> [--limit <number>] [--json] [--utc] [--delete [--force]]',
42
+ description: 'Retrieve or delete logs for a Sanity Function',
39
43
  async action(args, context) {
40
44
  const {apiClient, output} = context
41
- const {print} = output
45
+ const {print, error: printError} = output
46
+ const [name] = args.argsWithoutOptions
42
47
  const flags = {...defaultFlags, ...args.extOptions}
43
48
 
44
49
  const client = apiClient({
@@ -46,69 +51,97 @@ const logsFunctionsCommand: CliCommandDefinition = {
46
51
  requireProject: false,
47
52
  })
48
53
 
49
- if (flags.name === '') {
50
- throw new Error('You must provide a function name via the --name flag')
54
+ if (!name) {
55
+ throw new Error('You must provide a function name as the first argument')
51
56
  }
52
57
 
53
58
  const token = client.config().token
54
- const {blueprint} = await import('@sanity/runtime-cli/actions/blueprints')
59
+ if (!token) throw new Error('No API token found. Please run `sanity login`.')
60
+
61
+ const {getBlueprintAndStack} = await import('@sanity/runtime-cli/actions/blueprints')
55
62
  const {findFunction} = await import('@sanity/runtime-cli/utils')
56
63
 
57
- const {deployedStack} = await blueprint.readBlueprintOnDisk({
58
- getStack: true,
59
- token,
60
- })
64
+ const {deployedStack} = await getBlueprintAndStack({token})
61
65
 
62
66
  if (!deployedStack) {
63
67
  throw new Error('Stack not found')
64
68
  }
65
69
 
66
- const blueprintConfig = blueprint.readConfigFile()
67
- const projectId = blueprintConfig?.projectId
70
+ const {projectId} = deployedStack
68
71
 
69
- const {externalId} = findFunction.findFunctionByName(
70
- deployedStack,
71
- flags.name,
72
- ) as StackFunctionResource
72
+ const {externalId} = findFunction.findFunctionByName(deployedStack, name)
73
73
 
74
74
  if (token && projectId) {
75
75
  const {logs: logsAction} = await import('@sanity/runtime-cli/actions/functions')
76
- const {ok, error, logs, total} = await logsAction.logs(
77
- externalId,
78
- {limit: flags.limit},
79
- {token, projectId},
80
- )
81
-
82
- if (!ok) {
83
- print(`Error: ${error || 'Unknown error'}`)
84
- return
85
- }
86
76
 
87
- const filteredLogs = logs.filter(
88
- (entry: {level: string; message: string}) => entry.level && entry.message,
89
- )
77
+ if (!externalId) throw new Error('Unable to delete logs. Unable to determine function ID.')
78
+
79
+ if (flags.delete) {
80
+ if (!flags.force) {
81
+ const {certain} = await inquirer.prompt({
82
+ type: 'confirm',
83
+ name: 'certain',
84
+ message: `Are you sure you want to delete ${chalk.bold('all')} logs for function ${chalk.yellow(name)}?`,
85
+ default: false,
86
+ })
87
+ if (!certain) return
88
+ }
90
89
 
91
- if (filteredLogs.length === 0) {
92
- print(`No logs found for function ${flags.name}`)
93
- return
94
- }
90
+ print(`Deleting logs for function ${chalk.yellow(name)}`)
91
+ const {ok, error} = await logsAction.deleteLogs(externalId, {token, projectId})
95
92
 
96
- if (flags.json) {
97
- print(JSON.stringify(filteredLogs, null, 2))
93
+ if (!ok) {
94
+ printError(`${chalk.red('Failed')} to retrieve logs`)
95
+ printError(`Error: ${error || 'Unknown error'}`)
96
+ return
97
+ }
98
+
99
+ print('Logs deleted')
98
100
  } else {
99
- print(`Found ${total} log entries for function ${flags.name}`)
100
- if (logs.length < total) {
101
- print(`Here are the last ${filteredLogs.length} entries`)
101
+ print(`Finding logs for function "${name}"`)
102
+
103
+ const {ok, error, logs, total} = await logsAction.logs(
104
+ externalId,
105
+ {limit: flags.limit},
106
+ {token, projectId},
107
+ )
108
+
109
+ if (!ok) {
110
+ printError(`${chalk.red('Failed')} to retrieve logs`)
111
+ printError(`Error: ${error || 'Unknown error'}`)
112
+ return
113
+ }
114
+
115
+ const filteredLogs = logs.filter(
116
+ (entry: {level: string; message: string}) => entry.level && entry.message,
117
+ )
118
+
119
+ if (filteredLogs.length === 0) {
120
+ print(`No logs found for function ${name}`)
121
+ return
102
122
  }
103
- print('\n')
104
-
105
- for (const log of filteredLogs) {
106
- const {time, level, message} = log
107
- const date = new Date(time)
108
- const dateString = flags.utc
109
- ? date.toISOString().slice(0, 19).split('T').join(' ')
110
- : `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`
111
- print(`${dateString} ${level} ${message}`)
123
+
124
+ if (flags.json) {
125
+ print(JSON.stringify(filteredLogs, null, 2))
126
+ } else {
127
+ print(`Found ${total} log entries for function ${name}`)
128
+ if (logs.length < total) {
129
+ print(`Here are the last ${filteredLogs.length} entries`)
130
+ }
131
+ print('\n')
132
+
133
+ for (const log of filteredLogs) {
134
+ const {time, level, message} = log
135
+ const date = new Date(time)
136
+ const [dateString, timeString] = flags.utc
137
+ ? date.toISOString().slice(0, 19).split('T')
138
+ : [date.toLocaleDateString(), date.toLocaleTimeString()]
139
+ print(
140
+ [chalk.bold(dateString), chalk.bold.blue(timeString), logLevel(level), message].join(
141
+ ' ',
142
+ ),
143
+ )
144
+ }
112
145
  }
113
146
  }
114
147
  } else {
@@ -117,4 +150,14 @@ const logsFunctionsCommand: CliCommandDefinition = {
117
150
  },
118
151
  }
119
152
 
153
+ function logLevel(level: string) {
154
+ if (level === 'ERROR') {
155
+ return chalk.red(level)
156
+ }
157
+ if (level === 'WARN') {
158
+ return chalk.yellow(level)
159
+ }
160
+ return chalk.green(level)
161
+ }
162
+
120
163
  export default logsFunctionsCommand
@@ -1,76 +1,96 @@
1
1
  import {type CliCommandDefinition} from '../../types'
2
2
 
3
3
  const helpText = `
4
+ Arguments
5
+ <name> The name of the Sanity Function
6
+
4
7
  Options
5
8
  --data <data> Data to send to the function
6
9
  --file <file> Read data from file and send to the function
7
- --name <name> The name of your Sanity Function
8
10
  --timeout <timeout> Execution timeout value in seconds
11
+ --api <version> Sanity API Version to use
12
+ --dataset <dataset> The Sanity dataset to use
13
+ --project-id <id> Sanity Project ID to use
14
+
9
15
 
10
16
  Examples
11
17
  # Test function passing event data on command line
12
- sanity functions test --name echo --data '{ "id": 1 }'
18
+ sanity functions test echo --data '{ "id": 1 }'
13
19
 
14
20
  # Test function passing event data via a file
15
- sanity functions test -name echo --file 'payload.json'
21
+ sanity functions test echo --file 'payload.json'
16
22
 
17
23
  # Test function passing event data on command line and cap execution time to 60 seconds
18
- sanity functions test -name echo --data '{ "id": 1 }' --timeout 60
24
+ sanity functions test echo --data '{ "id": 1 }' --timeout 60
19
25
  `
20
26
 
21
27
  const defaultFlags = {
22
- data: undefined,
23
- file: undefined,
24
- name: '',
25
- timeout: 5, // seconds
28
+ 'data': undefined,
29
+ 'file': undefined,
30
+ 'timeout': 10, // seconds
31
+ 'api': undefined,
32
+ 'dataset': undefined,
33
+ 'project-id': undefined,
34
+ 'project': undefined,
35
+ 'projectId': undefined,
26
36
  }
27
37
 
28
38
  const testFunctionsCommand: CliCommandDefinition = {
29
39
  name: 'test',
30
40
  group: 'functions',
31
41
  helpText,
32
- signature: '',
42
+ signature:
43
+ '<name> [--data <json>] [--file <filename>] [--timeout <seconds>] [--api <version>] [--dataset <name>] [--project-id] <id>]',
33
44
  description: 'Invoke a local Sanity Function',
34
- hideFromHelp: true,
35
45
  async action(args, context) {
36
46
  const {output} = context
37
- const {print} = output
47
+ const {print, error: printError} = output
48
+ const [name] = args.argsWithoutOptions
38
49
  const flags = {...defaultFlags, ...args.extOptions}
39
50
 
40
- if (flags.name === '') {
41
- throw new Error('You must provide a function name via the --name flag')
51
+ if (!name) {
52
+ throw new Error('You must provide a function name as the first argument')
42
53
  }
43
54
 
44
55
  const {test} = await import('@sanity/runtime-cli/actions/functions')
45
56
  const {blueprint} = await import('@sanity/runtime-cli/actions/blueprints')
46
57
  const {findFunction} = await import('@sanity/runtime-cli/utils')
47
58
 
48
- const {parsedBlueprint} = await blueprint.readBlueprintOnDisk({
49
- getStack: false,
50
- })
59
+ const {parsedBlueprint} = await blueprint.readLocalBlueprint()
51
60
 
52
- const src = findFunction.getFunctionSource(parsedBlueprint, flags.name)
53
- if (!src) {
54
- throw new Error(`Error: Function ${flags.name} has no source code`)
55
- }
61
+ try {
62
+ const fn = findFunction.findFunctionByName(parsedBlueprint, name)
63
+ if (!fn) {
64
+ throw new Error(`Function ${name} has no source code`)
65
+ }
56
66
 
57
- const {json, logs, error} = await test.testAction(
58
- src,
59
- {
60
- data: flags.data,
61
- file: flags.file,
62
- timeout: flags.timeout,
63
- },
64
- {}, // @TODO: Add context
65
- )
67
+ const projectId = flags['project-id'] ?? flags.projectId ?? flags.project
68
+ const {json, logs, error} = await test.testAction(
69
+ fn,
70
+ {
71
+ data: flags.data,
72
+ file: flags.file,
73
+ timeout: flags.timeout,
74
+ },
75
+ {
76
+ clientOptions: {
77
+ apiVersion: flags.api,
78
+ dataset: flags.dataset,
79
+ projectId: projectId,
80
+ },
81
+ },
82
+ )
66
83
 
67
- if (error) {
68
- print(error.toString())
69
- } else {
70
- print('Logs:')
71
- print(logs)
72
- print('Response:')
73
- print(JSON.stringify(json, null, 2))
84
+ if (error) {
85
+ print(error.toString())
86
+ } else {
87
+ print('Logs:')
88
+ print(logs)
89
+ print('Response:')
90
+ print(JSON.stringify(json, null, 2))
91
+ }
92
+ } catch (error) {
93
+ printError(`Error: ${error || 'Unknown error'}`)
74
94
  }
75
95
  },
76
96
  }
@@ -3,6 +3,7 @@ import addBlueprintsCommand from './blueprints/addBlueprintsCommand'
3
3
  import blueprintsGroup from './blueprints/blueprintsGroup'
4
4
  import configBlueprintsCommand from './blueprints/configBlueprintsCommand'
5
5
  import deployBlueprintsCommand from './blueprints/deployBlueprintsCommand'
6
+ import destroyBlueprintsCommand from './blueprints/destroyBlueprintsCommand'
6
7
  import infoBlueprintsCommand from './blueprints/infoBlueprintsCommand'
7
8
  import initBlueprintsCommand from './blueprints/initBlueprintsCommand'
8
9
  import logsBlueprintsCommand from './blueprints/logsBlueprintsCommand'
@@ -59,12 +60,13 @@ export const baseCommands: (CliCommandDefinition | CliCommandGroupDefinition)[]
59
60
  testfunctionsCommand,
60
61
  envFunctionsCommand,
61
62
  blueprintsGroup,
63
+ addBlueprintsCommand,
64
+ configBlueprintsCommand,
65
+ deployBlueprintsCommand,
66
+ destroyBlueprintsCommand,
62
67
  infoBlueprintsCommand,
63
- listBlueprintsCommand,
64
68
  initBlueprintsCommand,
65
- deployBlueprintsCommand,
69
+ listBlueprintsCommand,
66
70
  logsBlueprintsCommand,
67
- addBlueprintsCommand,
68
- configBlueprintsCommand,
69
71
  planBlueprintsCommand,
70
72
  ]
@@ -23,7 +23,7 @@ export function ExampleComponent() {
23
23
  </Text>
24
24
  <Text muted>
25
25
  Looking for more guidance? See the <a href="https://sanity.io/ui">Sanity UI docs</a>{' '}
26
- and the <a href="https://sdk-docs.sanity.dev">Sanity App SDK docs</a>!
26
+ and the <a href="https://reference.sanity.io/_sanity/sdk-react/">Sanity App SDK docs</a>!
27
27
  </Text>
28
28
  </Stack>
29
29
  </Flex>