@sanity/runtime-cli 7.6.6 → 8.0.0

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.
Files changed (37) hide show
  1. package/README.md +65 -25
  2. package/bin/dev.cmd +1 -1
  3. package/bin/dev.js +1 -1
  4. package/dist/actions/blueprints/blueprint.d.ts +20 -2
  5. package/dist/actions/blueprints/blueprint.js +88 -35
  6. package/dist/actions/blueprints/resources.js +1 -13
  7. package/dist/actions/blueprints/stacks.d.ts +6 -0
  8. package/dist/actions/blueprints/stacks.js +17 -3
  9. package/dist/commands/blueprints/add.d.ts +1 -1
  10. package/dist/commands/blueprints/add.js +2 -5
  11. package/dist/commands/blueprints/config.js +1 -3
  12. package/dist/commands/blueprints/destroy.js +1 -4
  13. package/dist/commands/blueprints/info.js +1 -3
  14. package/dist/commands/blueprints/init.js +2 -6
  15. package/dist/commands/blueprints/stacks.d.ts +1 -2
  16. package/dist/commands/blueprints/stacks.js +3 -5
  17. package/dist/cores/blueprints/add.js +26 -7
  18. package/dist/cores/blueprints/config.js +3 -28
  19. package/dist/cores/blueprints/init.js +45 -75
  20. package/dist/cores/blueprints/plan.js +3 -3
  21. package/dist/cores/blueprints/stacks.d.ts +1 -1
  22. package/dist/cores/blueprints/stacks.js +2 -2
  23. package/dist/utils/display/blueprints-formatting.js +3 -3
  24. package/dist/utils/display/presenters.d.ts +1 -0
  25. package/dist/utils/display/presenters.js +6 -3
  26. package/dist/utils/display/prompt.d.ts +4 -0
  27. package/dist/utils/display/prompt.js +44 -1
  28. package/dist/utils/invoke-local.js +2 -0
  29. package/dist/utils/other/npmjs.d.ts +1 -0
  30. package/dist/utils/other/npmjs.js +13 -0
  31. package/dist/utils/types.d.ts +1 -1
  32. package/oclif.manifest.json +18 -19
  33. package/package.json +6 -7
  34. package/dist/utils/format-error.d.ts +0 -4
  35. package/dist/utils/format-error.js +0 -9
  36. package/dist/utils/is-dependency.d.ts +0 -1
  37. package/dist/utils/is-dependency.js +0 -7
@@ -5,13 +5,11 @@ export default class InfoCommand extends DeployedBlueprintCommand {
5
5
  static description = 'Show information about a Blueprint deployment';
6
6
  static examples = [
7
7
  '<%= config.bin %> <%= command.id %>',
8
- // LAUNCH LIMIT: 1 Stack per Project - do not allow Stack ID to be set
9
- // '<%= config.bin %> <%= command.id %> --id ST-a1b2c3',
8
+ '<%= config.bin %> <%= command.id %> --stack-id <stackId>',
10
9
  ];
11
10
  static flags = {
12
11
  id: Flags.string({
13
12
  description: 'Stack ID to show info for (defaults to current stack)',
14
- hidden: true, // LAUNCH LIMIT: 1 Stack per Project
15
13
  }),
16
14
  };
17
15
  async run() {
@@ -7,10 +7,8 @@ export default class InitCommand extends Command {
7
7
  '<%= config.bin %> <%= command.id %>',
8
8
  '<%= config.bin %> <%= command.id %> [directory]',
9
9
  '<%= config.bin %> <%= command.id %> --blueprint-type <json|js|ts>',
10
- '<%= config.bin %> <%= command.id %> --blueprint-type <json|js|ts> --project-id <projectId>',
11
- // LAUNCH LIMIT: 1 Stack per Project - do not prompt for Stack, just create one
12
- // '<%= config.bin %> <%= command.id %> --blueprint-type <json|js|ts> --project-id <projectId> --stack-id <stackId>',
13
- // '<%= config.bin %> <%= command.id %> --blueprint-type <json|js|ts> --project-id <projectId> --stack-name <stackName>',
10
+ '<%= config.bin %> <%= command.id %> --blueprint-type <json|js|ts> --project-id <projectId> --stack-id <stackId>',
11
+ '<%= config.bin %> <%= command.id %> --blueprint-type <json|js|ts> --stack-name <stackName>',
14
12
  ];
15
13
  static args = {
16
14
  dir: Args.string({
@@ -35,13 +33,11 @@ export default class InitCommand extends Command {
35
33
  aliases: ['stack', 'stackId'],
36
34
  dependsOn: ['project-id'],
37
35
  exclusive: ['stack-name'],
38
- hidden: true, // LAUNCH LIMIT: 1 Stack per Project
39
36
  }),
40
37
  'stack-name': Flags.string({
41
38
  description: 'Name to use for a NEW Stack',
42
39
  aliases: ['name'],
43
40
  exclusive: ['stack-id'],
44
- hidden: true, // LAUNCH LIMIT: 1 Stack per Project
45
41
  }),
46
42
  };
47
43
  async run() {
@@ -1,10 +1,9 @@
1
1
  import { BlueprintCommand } from '../../baseCommands.js';
2
2
  export default class StacksCommand extends BlueprintCommand<typeof StacksCommand> {
3
- static hidden: boolean;
4
3
  static description: string;
5
4
  static examples: string[];
6
5
  static flags: {
7
- projectId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ 'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
7
  };
9
8
  run(): Promise<void>;
10
9
  }
@@ -2,17 +2,15 @@ import { Flags } from '@oclif/core';
2
2
  import { BlueprintCommand } from '../../baseCommands.js';
3
3
  import { blueprintStacksCore } from '../../cores/blueprints/stacks.js';
4
4
  export default class StacksCommand extends BlueprintCommand {
5
- // LAUNCH LIMIT: 1 Stack per Project - hide stacks command
6
- static hidden = true;
7
5
  static description = 'List all Blueprint stacks';
8
6
  static examples = [
9
7
  '<%= config.bin %> <%= command.id %>',
10
- '<%= config.bin %> <%= command.id %> --projectId a1b2c3',
8
+ '<%= config.bin %> <%= command.id %> --project-id <projectId>',
11
9
  ];
12
10
  static flags = {
13
- projectId: Flags.string({
11
+ 'project-id': Flags.string({
14
12
  description: 'Project ID to show stacks for',
15
- required: false,
13
+ aliases: ['projectId', 'project'],
16
14
  }),
17
15
  };
18
16
  async run() {
@@ -1,9 +1,21 @@
1
1
  import { cwd } from 'node:process';
2
+ import { highlight } from 'cardinal';
2
3
  import chalk from 'chalk';
3
- import highlight from 'color-json';
4
4
  import inquirer from 'inquirer';
5
5
  import { createFunctionResource } from '../../actions/blueprints/resources.js';
6
6
  import { validateFunctionName } from '../../utils/validate/resource.js';
7
+ const FUNCTION_BLUEPRINT_RESOURCE_TEMPLATE = `
8
+ import {defineBlueprint, defineDocumentFunction} from '@sanity/blueprints'
9
+ // update imports ↑
10
+
11
+ export default defineBlueprint({
12
+ // ...
13
+ resources: [
14
+ // ...
15
+ defineDocumentFunction({name: '{{fnName}}'}), // ← add this line
16
+ ],
17
+ })
18
+ `;
7
19
  export async function blueprintAddCore(options) {
8
20
  const { bin = 'sanity', log, blueprint, args, flags } = options;
9
21
  const { type: resourceType } = args;
@@ -89,17 +101,24 @@ export async function blueprintAddCore(options) {
89
101
  });
90
102
  log(`\nCreated function: ${filePath.replace(cwd(), '')}`);
91
103
  if (!resourceAdded) {
92
- // print the resource JSON for manual addition
93
- log('\nAdd this Function resource to your Blueprint:');
94
- log(highlight(JSON.stringify(resource, null, 2), undefined, undefined, 2));
104
+ // print the resource definition for manual addition
105
+ log(`\n${chalk.bold('Add the Resource to your Blueprint:')}`);
106
+ switch (blueprint.fileInfo.extension) {
107
+ case '.ts':
108
+ log(highlight(FUNCTION_BLUEPRINT_RESOURCE_TEMPLATE.replace('{{fnName}}', fnName)));
109
+ break;
110
+ case '.js':
111
+ log(highlight(FUNCTION_BLUEPRINT_RESOURCE_TEMPLATE.replace('{{fnName}}', fnName)));
112
+ break;
113
+ default:
114
+ log(highlight(JSON.stringify(resource, null, 2)));
115
+ break;
116
+ }
95
117
  }
96
118
  else {
97
119
  // added to blueprint.json
98
120
  log(`Function "${chalk.bold(fnName)}" added to Blueprint file.`);
99
121
  }
100
- if (fnLang === 'ts') {
101
- log(chalk.dim('Add "functions/**/.build/**" to your .gitignore.'));
102
- }
103
122
  return { success: true };
104
123
  }
105
124
  catch (err) {
@@ -1,9 +1,9 @@
1
+ import { highlight } from 'cardinal';
1
2
  import chalk from 'chalk';
2
- import highlight from 'color-json';
3
3
  import inquirer from 'inquirer';
4
4
  import ora from 'ora';
5
5
  import { BLUEPRINT_CONFIG_FILE, BLUEPRINT_DIR, writeConfigFile, } from '../../actions/blueprints/blueprint.js';
6
- import { createStack, getStack, listStacks } from '../../actions/blueprints/stacks.js';
6
+ import { createStack, getStack } from '../../actions/blueprints/stacks.js';
7
7
  import { getProject } from '../../actions/sanity/projects.js';
8
8
  import { niceId, warn } from '../../utils/display/presenters.js';
9
9
  import { promptForProject } from '../../utils/display/prompt.js';
@@ -67,7 +67,7 @@ export async function blueprintConfigCore(options) {
67
67
  // LAUNCH LIMIT: 1 Stack per Project - configStackId is always inferred from projectId if not set in config JSON
68
68
  let updatedStackId = flagStackId ?? // flag first
69
69
  configStackId ?? // existing config second
70
- `ST-${updatedProjectId}`; /*??*/ // LAUNCH LIMIT: 1 Stack per Project - project-based third
70
+ `ST-${updatedProjectId}`; //?? LAUNCH LIMIT: 1 Stack per Project - project-based third
71
71
  // (await promptForStackId({projectId: updatedProjectId, knownStackId: configStackId})) // prompt for stackId
72
72
  const isProjectBasedId = updatedStackId === `ST-${updatedProjectId}`;
73
73
  log(`\n${chalk.bold('New configuration:')}`);
@@ -135,31 +135,6 @@ export async function blueprintConfigCore(options) {
135
135
  return { success: false, error: 'Unknown error' };
136
136
  }
137
137
  }
138
- async function promptForStackId({ token, projectId, knownStackId, }) {
139
- const auth = { token, projectId };
140
- // get stacks for selected project
141
- const { ok: stacksOk, stacks, error: stacksError } = await listStacks(auth);
142
- if (!stacksOk)
143
- throw new Error(stacksError ?? 'Unknown error listing stacks');
144
- if (stacks.length > 0) {
145
- const stackChoices = stacks.map((s) => ({
146
- name: `"${s.name}" ${niceId(s.id)} ${chalk.dim(`(${s.resources.length} res)`)}`,
147
- value: s.id,
148
- }));
149
- stackChoices.push({ name: 'Unset Stack association', value: 'unset' });
150
- const { pickedStackId } = await inquirer.prompt([
151
- {
152
- type: 'list',
153
- name: 'pickedStackId',
154
- message: 'Select a stack:',
155
- choices: stackChoices,
156
- default: knownStackId,
157
- },
158
- ]);
159
- return pickedStackId === 'unset' ? undefined : pickedStackId;
160
- }
161
- return undefined;
162
- }
163
138
  async function testConfigAndReport({ token, stackId, projectId, }) {
164
139
  const spinner = ora('Testing the configuration...').start();
165
140
  const { ok, error } = await getStack({
@@ -2,18 +2,18 @@ import { join } from 'node:path';
2
2
  import { cwd } from 'node:process';
3
3
  import chalk from 'chalk';
4
4
  import inquirer from 'inquirer';
5
- import { BLUEPRINT_CONFIG_FILE, BLUEPRINT_DIR, findBlueprintFile, writeBlueprintToDisk, writeConfigFile, } from '../../actions/blueprints/blueprint.js';
6
- import { createStack, getStack, listStacks } from '../../actions/blueprints/stacks.js';
5
+ import { BLUEPRINT_CONFIG_FILE, BLUEPRINT_DIR, findBlueprintFile, writeBlueprintToDisk, writeConfigFile, writeGitignoreFile, writeOrUpdateNodeDependency, } from '../../actions/blueprints/blueprint.js';
6
+ import { createEmptyStack, getStack } from '../../actions/blueprints/stacks.js';
7
7
  import { getProject } from '../../actions/sanity/projects.js';
8
- import { niceId } from '../../utils/display/presenters.js';
9
- import { promptForProject } from '../../utils/display/prompt.js';
8
+ import { check, warn } from '../../utils/display/presenters.js';
9
+ import { promptForProject, promptForStackId } from '../../utils/display/prompt.js';
10
10
  const LAUNCH_LIMIT_STACK_PER_PROJECT = true;
11
11
  export async function blueprintInitCore(options) {
12
- const { log, token, args, flags } = options;
12
+ const { bin = 'sanity', log, token, args, flags } = options;
13
13
  try {
14
14
  const { 'blueprint-type': flagBlueprintType, 'project-id': flagProjectId, 'stack-id': flagStackId, 'stack-name': flagStackName, dir: flagDir, } = flags;
15
15
  const { dir: argDir } = args;
16
- const dirProvided = argDir || flagDir;
16
+ const providedDir = argDir || flagDir;
17
17
  const here = cwd();
18
18
  const dir = argDir || flagDir || here;
19
19
  const existingBlueprint = findBlueprintFile(dir);
@@ -30,6 +30,7 @@ export async function blueprintInitCore(options) {
30
30
  const pickedProject = await promptForProject({ token });
31
31
  projectId = pickedProject.projectId;
32
32
  }
33
+ log('');
33
34
  if (flagStackName) {
34
35
  // using --stack-name gets around "LAUNCH LIMIT: 1 Stack per Project"
35
36
  const stack = await createEmptyStack({
@@ -51,17 +52,40 @@ export async function blueprintInitCore(options) {
51
52
  stackId = await promptForStackId({ projectId, token });
52
53
  }
53
54
  }
54
- const fileName = `blueprint.${blueprintExtension}`;
55
+ const fileName = `sanity.blueprint.${blueprintExtension}`;
55
56
  const filePath = join(dir, fileName);
56
- if (dirProvided)
57
- log(`New Blueprint created: ${dirProvided}/`);
58
- writeBlueprintToDisk({ blueprintFilePath: filePath });
59
- log(`Created new blueprint: ${dirProvided ?? '.'}/${fileName}`);
57
+ writeBlueprintToDisk({
58
+ blueprintFilePath: filePath,
59
+ // content: {resources: [] /*projectId, stackId*/}, // TODO: in the future maybe set config in blueprint
60
+ });
61
+ if (providedDir)
62
+ log(check(`${chalk.bold('New folder created:')} ${providedDir}/`));
63
+ log(check(`${chalk.bold('Created Blueprint:')} ${providedDir ?? '.'}/${fileName}`));
60
64
  writeConfigFile({ blueprintFilePath: filePath, projectId, stackId });
61
- log(`Created new config file: ${dirProvided ?? '.'}/${BLUEPRINT_DIR}/${BLUEPRINT_CONFIG_FILE}`);
62
- if (blueprintExtension === 'ts') {
63
- log('\nNote: TypeScript support requires "tsx" to be installed. Run: npm install -D tsx');
65
+ log(check(`${chalk.bold('Added configuration:')} ${providedDir ?? '.'}/${BLUEPRINT_DIR}/${BLUEPRINT_CONFIG_FILE}`));
66
+ writeGitignoreFile({ blueprintFilePath: filePath });
67
+ log(check(`${chalk.bold('Added .gitignore:')} ${providedDir ?? '.'}/.gitignore`));
68
+ if (blueprintExtension !== 'json') {
69
+ try {
70
+ // check for || create package.json and add @sanity/blueprints to dependencies
71
+ await writeOrUpdateNodeDependency({
72
+ blueprintFilePath: filePath,
73
+ dependency: '@sanity/blueprints',
74
+ });
75
+ log(check(`${chalk.bold('Added dependency:')} @sanity/blueprints`));
76
+ }
77
+ catch (err) {
78
+ log(warn('Unable to add @sanity/blueprints to your project.'));
79
+ }
64
80
  }
81
+ const nextStepParts = [];
82
+ if (providedDir)
83
+ nextStepParts.push(`cd ./${providedDir}`);
84
+ if (blueprintExtension !== 'json')
85
+ nextStepParts.push('npm install');
86
+ nextStepParts.push(`${bin} blueprints --help`);
87
+ const nextStep = `Run \`${nextStepParts.join(' && ')}\``;
88
+ log(`\n ${chalk.dim(nextStep)} to get started`);
65
89
  return { success: true };
66
90
  }
67
91
  catch (error) {
@@ -75,72 +99,17 @@ async function promptForBlueprintType() {
75
99
  {
76
100
  type: 'list',
77
101
  name: 'pickedBlueprintsType',
78
- message: 'Choose a blueprint type:',
102
+ message: 'Choose a Blueprint file type:',
79
103
  choices: [
104
+ { name: 'TypeScript', value: 'ts' },
105
+ { name: 'JavaScript', value: 'js' },
80
106
  { name: 'JSON', value: 'json' },
81
- { name: 'TypeScript', value: 'ts', disabled: '(Coming soon)' },
82
- { name: 'JavaScript', value: 'js', disabled: '(Coming soon)' },
83
107
  ],
84
- default: 'json',
108
+ default: 'ts',
85
109
  },
86
110
  ]);
87
111
  return pickedBlueprintsType;
88
112
  }
89
- async function promptForStackId({ projectId, token, }) {
90
- const { ok: stacksOk, error: stacksErr, stacks } = await listStacks({ token, projectId });
91
- if (!stacksOk) {
92
- throw new Error(stacksErr || 'Failed to list Stacks');
93
- }
94
- const stackChoices = [
95
- { name: chalk.bold('✨ Create a new Stack'), value: 'new' },
96
- ];
97
- if (stacks.length > 0) {
98
- stackChoices.push(new inquirer.Separator(chalk.underline('Use an existing Stack:')));
99
- stackChoices.push(...stacks.map((s) => ({
100
- name: `"${s.name}" ${niceId(s.id)} ${chalk.dim(`(${s.resources.length} res)`)}`,
101
- value: s.id,
102
- })));
103
- }
104
- const { pickedStackId } = await inquirer.prompt([
105
- {
106
- type: 'list',
107
- name: 'pickedStackId',
108
- message: 'Select an existing deployment or create a new one:',
109
- choices: stackChoices,
110
- },
111
- ]);
112
- if (pickedStackId === 'new') {
113
- const { stackName } = await inquirer.prompt([
114
- {
115
- type: 'input',
116
- name: 'stackName',
117
- message: 'Enter a name for your Stack:',
118
- validate: (input) => input.length > 0 || 'Stack name is required',
119
- },
120
- ]);
121
- const stack = await createEmptyStack({
122
- token,
123
- projectId,
124
- name: stackName,
125
- });
126
- return stack.id;
127
- }
128
- return pickedStackId;
129
- }
130
- async function createEmptyStack({ token, projectId, name, projectBased = true, }) {
131
- const stackPayload = {
132
- name,
133
- projectId,
134
- useProjectBasedId: projectBased,
135
- document: { resources: [] },
136
- };
137
- const auth = { token, projectId };
138
- const response = await createStack({ stackPayload, auth });
139
- if (!response.ok) {
140
- throw new Error(response.error || 'Failed to create new Stack');
141
- }
142
- return response.stack;
143
- }
144
113
  // LAUNCH LIMIT: 1 Stack per Project - create exclusive stack for project
145
114
  async function createProjectBasedStack(auth, token, log) {
146
115
  const { projectId } = auth;
@@ -155,8 +124,9 @@ async function createProjectBasedStack(auth, token, log) {
155
124
  const { stack: existingStack, ok: stackOk } = await getStack({ stackId: inferredStackId, auth });
156
125
  // if existing stack, return stack
157
126
  if (stackOk && existingStack) {
158
- log(chalk.red(`Found existing deployment for "${projectDisplayName}" Blueprint`));
159
- log(chalk.red('Deploying an empty Blueprint will override the existing deployment.'));
127
+ log(warn(`"${projectDisplayName}" has an existing deployment.`));
128
+ log(warn(`Deploying an empty Blueprint ${chalk.bold.red('will override the existing deployment!')}`));
129
+ log('');
160
130
  return existingStack;
161
131
  }
162
132
  // if not, create a stack
@@ -1,10 +1,10 @@
1
1
  import chalk from 'chalk';
2
2
  import { getStack } from '../../actions/blueprints/stacks.js';
3
- import { formatResourceTree, formatTitle, stackDeployDiff, } from '../../utils/display/blueprints-formatting.js';
3
+ import { formatResourceTree, stackDeployDiff } from '../../utils/display/blueprints-formatting.js';
4
4
  export async function blueprintPlanCore(options) {
5
5
  const { bin = 'sanity', log, blueprint, token } = options;
6
6
  const { projectId, stackId, parsedBlueprint, fileInfo } = blueprint;
7
- log(`${formatTitle('Deployment', 'Plan')} ${chalk.dim(`(${fileInfo.fileName})`)}`);
7
+ log(`${chalk.bold.blueBright('Blueprint Deployment Plan')} ${chalk.dim(`(${fileInfo.fileName})`)}`);
8
8
  log(formatResourceTree(parsedBlueprint.resources));
9
9
  if (token && projectId && stackId) {
10
10
  const stackResponse = await getStack({ stackId, auth: { token, projectId } });
@@ -19,6 +19,6 @@ export async function blueprintPlanCore(options) {
19
19
  log(chalk.dim('No changes detected to live deployment'));
20
20
  }
21
21
  }
22
- log(chalk.dim(`Run ${bin} blueprints deploy to deploy these changes`));
22
+ log(chalk.dim(`Run "${bin} blueprints deploy" to deploy these changes`));
23
23
  return { success: true };
24
24
  }
@@ -4,7 +4,7 @@ export interface BlueprintStacksOptions extends CoreConfig {
4
4
  token: string;
5
5
  blueprint: ReadBlueprintResult;
6
6
  flags: {
7
- projectId?: string;
7
+ 'project-id'?: string;
8
8
  };
9
9
  }
10
10
  export declare function blueprintStacksCore(options: BlueprintStacksOptions): Promise<CoreResult>;
@@ -5,9 +5,9 @@ import { niceId } from '../../utils/display/presenters.js';
5
5
  export async function blueprintStacksCore(options) {
6
6
  const { log, token, blueprint, flags } = options;
7
7
  const { projectId: blueprintProjectId, stackId: blueprintStackId } = blueprint;
8
- const projectId = flags.projectId || blueprintProjectId;
8
+ const projectId = flags['project-id'] || blueprintProjectId;
9
9
  if (!projectId) {
10
- log('Run in a Blueprint directory or provide a Project with --projectId');
10
+ log('Run in a Blueprint directory or provide a Project with --project-id');
11
11
  return { success: false, error: 'No Project ID provided' };
12
12
  }
13
13
  try {
@@ -9,7 +9,7 @@ export function formatTitle(title, name) {
9
9
  export function formatResourceTree(resources) {
10
10
  if (!resources || resources.length === 0)
11
11
  return ' Zero resources';
12
- const output = [`${chalk.blue('Blueprint Resources')} [${resources.length}]`];
12
+ const output = [`${chalk.bold.underline('Resources')} [${resources.length}]`];
13
13
  const functionResources = resources.filter((r) => r.type?.startsWith('sanity.function.'));
14
14
  const otherResources = resources.filter((r) => !r.type?.startsWith('sanity.function.'));
15
15
  const hasOtherResources = otherResources.length > 0;
@@ -17,12 +17,12 @@ export function formatResourceTree(resources) {
17
17
  const fnsOutput = [`${chalk.bold('Functions')} [${functionResources.length}]`];
18
18
  const fnDetails = [];
19
19
  for (const fn of functionResources) {
20
- const name = chalk.green(fn.displayName || fn.name);
20
+ const name = chalk.bold.green(fn.displayName || fn.name);
21
21
  const ids = [
22
22
  'id' in fn && fn.id ? `${niceId(fn.id)}` : '',
23
23
  'externalId' in fn && fn.externalId ? `<${niceId(fn.externalId)}>` : '',
24
24
  ].join(' ');
25
- fnDetails.push(`"${name}" ${ids}`);
25
+ fnDetails.push(`${name} ${ids}`);
26
26
  if ('parameters' in fn && fn.parameters) {
27
27
  fnDetails.push(arrayifyStackFunction(fn));
28
28
  }
@@ -1,3 +1,4 @@
1
+ export declare function check(str: string): string;
1
2
  export declare function info(str: string): string;
2
3
  export declare function warn(str: string): string;
3
4
  export declare function severe(str: string): string;
@@ -1,12 +1,15 @@
1
1
  import chalk from 'chalk';
2
+ export function check(str) {
3
+ return `${chalk.bold(chalk.green('✔︎'))} ${str}`;
4
+ }
2
5
  export function info(str) {
3
- return `${chalk.blue('')} ${str}`;
6
+ return `${chalk.bold.blue('ℹ︎')} ${str}`;
4
7
  }
5
8
  export function warn(str) {
6
- return `${chalk.yellow('')} ${str}`;
9
+ return `${chalk.bold.yellow('▶︎')} ${str}`;
7
10
  }
8
11
  export function severe(str) {
9
- return `${chalk.red('')} ${str}`;
12
+ return `${chalk.bold.red('')} ${str}`;
10
13
  }
11
14
  export function niceId(id) {
12
15
  if (!id)
@@ -12,3 +12,7 @@ export declare function promptForProject({ token, knownOrganizationId, knownProj
12
12
  projectId: string;
13
13
  displayName: string;
14
14
  }>;
15
+ export declare function promptForStackId({ projectId, token, }: {
16
+ projectId: string;
17
+ token: string;
18
+ }): Promise<string>;
@@ -1,4 +1,6 @@
1
+ import chalk from 'chalk';
1
2
  import inquirer from 'inquirer';
3
+ import { createEmptyStack, listStacks } from '../../actions/blueprints/stacks.js';
2
4
  import { groupProjectsByOrganization } from '../../actions/sanity/projects.js';
3
5
  import { niceId } from './presenters.js';
4
6
  /**
@@ -44,10 +46,51 @@ export async function promptForProject({ token, knownOrganizationId, knownProjec
44
46
  {
45
47
  type: 'list',
46
48
  name: 'pickedProject',
47
- message: 'Which Project would you like to use?',
49
+ message: 'Choose a Sanity Project:',
48
50
  choices: projectChoices,
49
51
  default: knownProjectId,
50
52
  },
51
53
  ]);
52
54
  return pickedProject;
53
55
  }
56
+ export async function promptForStackId({ projectId, token, }) {
57
+ const { ok: stacksOk, error: stacksErr, stacks } = await listStacks({ token, projectId });
58
+ if (!stacksOk) {
59
+ throw new Error(stacksErr || 'Failed to list Stacks');
60
+ }
61
+ const stackChoices = [
62
+ { name: chalk.bold('✨ Create a new Stack'), value: 'new' },
63
+ ];
64
+ if (stacks.length > 0) {
65
+ stackChoices.push(new inquirer.Separator(chalk.underline('Use an existing Stack:')));
66
+ stackChoices.push(...stacks.map((s) => ({
67
+ name: `"${s.name}" ${niceId(s.id)} ${chalk.dim(`(${s.resources.length} res)`)}`,
68
+ value: s.id,
69
+ })));
70
+ }
71
+ const { pickedStackId } = await inquirer.prompt([
72
+ {
73
+ type: 'list',
74
+ name: 'pickedStackId',
75
+ message: 'Select an existing deployment or create a new one:',
76
+ choices: stackChoices,
77
+ },
78
+ ]);
79
+ if (pickedStackId === 'new') {
80
+ const { stackName } = await inquirer.prompt([
81
+ {
82
+ type: 'input',
83
+ name: 'stackName',
84
+ message: 'Enter a name for your Stack:',
85
+ validate: (input) => input.length > 0 || 'Stack name is required',
86
+ },
87
+ ]);
88
+ const stack = await createEmptyStack({
89
+ token,
90
+ projectId,
91
+ name: stackName,
92
+ });
93
+ return stack.id;
94
+ }
95
+ return pickedStackId;
96
+ }
@@ -47,6 +47,8 @@ export async function applyGroqRule(resource, data) {
47
47
  throw Error('⚠️ failed parsing/evaluating GROQ rule! Skipping invoke.');
48
48
  }
49
49
  }
50
+ // default groq rule so just return the data
51
+ return data;
50
52
  }
51
53
  export default async function invoke(resource, data, context, options) {
52
54
  if (!resource.src) {
@@ -0,0 +1 @@
1
+ export declare function getLatestNpmVersion(pkg: string): Promise<string>;
@@ -0,0 +1,13 @@
1
+ export async function getLatestNpmVersion(pkg) {
2
+ const url = `https://registry.npmjs.org/${pkg}/latest`;
3
+ try {
4
+ const res = await fetch(url);
5
+ if (!res.ok)
6
+ throw new Error(`Failed to fetch version for ${pkg}`);
7
+ const data = await res.json();
8
+ return data.version;
9
+ }
10
+ catch (error) {
11
+ return 'latest';
12
+ }
13
+ }
@@ -141,7 +141,7 @@ export interface InvokeExecutionOptions {
141
141
  /** @internal */
142
142
  export interface InvocationResponse {
143
143
  error: undefined | unknown;
144
- json: object | undefined;
144
+ json: Record<string, unknown> | undefined;
145
145
  logs: string | undefined;
146
146
  timings?: Record<string, number>;
147
147
  }