@sanity/runtime-cli 12.4.0 → 13.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 (111) hide show
  1. package/README.md +176 -63
  2. package/dist/actions/blueprints/assets.d.ts +3 -1
  3. package/dist/actions/blueprints/assets.js +8 -4
  4. package/dist/actions/blueprints/blueprint.d.ts +2 -1
  5. package/dist/actions/blueprints/blueprint.js +3 -1
  6. package/dist/actions/blueprints/config.d.ts +5 -2
  7. package/dist/actions/blueprints/config.js +4 -4
  8. package/dist/actions/blueprints/logs-streaming.d.ts +4 -2
  9. package/dist/actions/blueprints/logs-streaming.js +5 -2
  10. package/dist/actions/blueprints/logs.d.ts +2 -1
  11. package/dist/actions/blueprints/logs.js +4 -2
  12. package/dist/actions/blueprints/resources.d.ts +2 -1
  13. package/dist/actions/blueprints/resources.js +2 -2
  14. package/dist/actions/blueprints/stacks.d.ts +12 -6
  15. package/dist/actions/blueprints/stacks.js +18 -11
  16. package/dist/actions/functions/dev.d.ts +2 -1
  17. package/dist/actions/functions/dev.js +2 -2
  18. package/dist/actions/functions/env/list.d.ts +2 -1
  19. package/dist/actions/functions/env/list.js +4 -2
  20. package/dist/actions/functions/env/remove.d.ts +2 -1
  21. package/dist/actions/functions/env/remove.js +4 -2
  22. package/dist/actions/functions/env/update.d.ts +2 -1
  23. package/dist/actions/functions/env/update.js +4 -2
  24. package/dist/actions/functions/logs.d.ts +4 -3
  25. package/dist/actions/functions/logs.js +10 -6
  26. package/dist/actions/node.d.ts +2 -1
  27. package/dist/actions/node.js +2 -2
  28. package/dist/actions/sanity/examples.d.ts +5 -2
  29. package/dist/actions/sanity/examples.js +6 -6
  30. package/dist/actions/sanity/projects.d.ts +7 -3
  31. package/dist/actions/sanity/projects.js +11 -7
  32. package/dist/baseCommands.d.ts +4 -0
  33. package/dist/baseCommands.js +8 -2
  34. package/dist/commands/blueprints/add.d.ts +1 -0
  35. package/dist/commands/blueprints/add.js +12 -8
  36. package/dist/commands/blueprints/config.d.ts +1 -0
  37. package/dist/commands/blueprints/config.js +10 -4
  38. package/dist/commands/blueprints/deploy.d.ts +1 -0
  39. package/dist/commands/blueprints/deploy.js +8 -2
  40. package/dist/commands/blueprints/destroy.d.ts +1 -0
  41. package/dist/commands/blueprints/destroy.js +8 -2
  42. package/dist/commands/blueprints/doctor.d.ts +1 -0
  43. package/dist/commands/blueprints/doctor.js +7 -2
  44. package/dist/commands/blueprints/info.d.ts +1 -0
  45. package/dist/commands/blueprints/info.js +9 -3
  46. package/dist/commands/blueprints/init.d.ts +1 -0
  47. package/dist/commands/blueprints/init.js +20 -11
  48. package/dist/commands/blueprints/logs.d.ts +1 -0
  49. package/dist/commands/blueprints/logs.js +8 -2
  50. package/dist/commands/blueprints/plan.d.ts +1 -0
  51. package/dist/commands/blueprints/plan.js +6 -2
  52. package/dist/commands/blueprints/stacks.d.ts +1 -0
  53. package/dist/commands/blueprints/stacks.js +8 -4
  54. package/dist/commands/functions/add.d.ts +1 -0
  55. package/dist/commands/functions/add.js +8 -2
  56. package/dist/commands/functions/dev.d.ts +1 -0
  57. package/dist/commands/functions/dev.js +14 -3
  58. package/dist/commands/functions/env/add.d.ts +2 -1
  59. package/dist/commands/functions/env/add.js +6 -2
  60. package/dist/commands/functions/env/list.d.ts +2 -1
  61. package/dist/commands/functions/env/list.js +6 -2
  62. package/dist/commands/functions/env/remove.d.ts +2 -1
  63. package/dist/commands/functions/env/remove.js +6 -2
  64. package/dist/commands/functions/logs.d.ts +2 -1
  65. package/dist/commands/functions/logs.js +7 -4
  66. package/dist/commands/functions/test.d.ts +2 -1
  67. package/dist/commands/functions/test.js +6 -2
  68. package/dist/cores/blueprints/config.js +9 -9
  69. package/dist/cores/blueprints/deploy.js +14 -16
  70. package/dist/cores/blueprints/destroy.js +6 -6
  71. package/dist/cores/blueprints/doctor.js +20 -27
  72. package/dist/cores/blueprints/info.js +3 -3
  73. package/dist/cores/blueprints/init.d.ts +3 -3
  74. package/dist/cores/blueprints/init.js +15 -8
  75. package/dist/cores/blueprints/logs.js +6 -7
  76. package/dist/cores/blueprints/plan.js +1 -0
  77. package/dist/cores/blueprints/stacks.js +4 -4
  78. package/dist/cores/functions/add.js +8 -3
  79. package/dist/cores/functions/dev.js +2 -2
  80. package/dist/cores/functions/env/add.js +3 -4
  81. package/dist/cores/functions/env/list.js +3 -4
  82. package/dist/cores/functions/env/remove.js +3 -4
  83. package/dist/cores/functions/index.d.ts +3 -9
  84. package/dist/cores/functions/logs.js +8 -9
  85. package/dist/cores/functions/test.js +7 -8
  86. package/dist/cores/index.d.ts +4 -7
  87. package/dist/cores/index.js +3 -3
  88. package/dist/index.d.ts +1 -2
  89. package/dist/index.js +1 -2
  90. package/dist/server/app.d.ts +2 -1
  91. package/dist/server/app.js +4 -4
  92. package/dist/server/handlers/invoke.d.ts +2 -1
  93. package/dist/server/handlers/invoke.js +2 -2
  94. package/dist/utils/display/prompt.d.ts +5 -2
  95. package/dist/utils/display/prompt.js +5 -4
  96. package/dist/utils/functions/fetch-document.d.ts +3 -2
  97. package/dist/utils/functions/fetch-document.js +7 -6
  98. package/dist/utils/index.d.ts +2 -0
  99. package/dist/utils/index.js +2 -0
  100. package/dist/utils/logger.d.ts +13 -0
  101. package/dist/utils/logger.js +61 -0
  102. package/dist/utils/other/github.d.ts +2 -1
  103. package/dist/utils/other/github.js +4 -2
  104. package/dist/utils/other/npmjs.d.ts +2 -1
  105. package/dist/utils/other/npmjs.js +4 -2
  106. package/dist/utils/traced-fetch.d.ts +35 -0
  107. package/dist/utils/traced-fetch.js +238 -0
  108. package/dist/utils/validated-token.d.ts +3 -2
  109. package/dist/utils/validated-token.js +6 -4
  110. package/oclif.manifest.json +175 -38
  111. package/package.json +13 -5
@@ -1,9 +1,10 @@
1
1
  import { DeployedStackCommand } from '../../../baseCommands.js';
2
2
  export default class EnvListCommand extends DeployedStackCommand<typeof EnvListCommand> {
3
+ static summary: string;
4
+ static description: string;
3
5
  static args: {
4
6
  name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
7
  };
6
- static description: string;
7
8
  static examples: string[];
8
9
  run(): Promise<void>;
9
10
  }
@@ -1,16 +1,20 @@
1
1
  import { Args } from '@oclif/core';
2
2
  import { DeployedStackCommand } from '../../../baseCommands.js';
3
3
  import { functionEnvListCore } from '../../../cores/functions/env/list.js';
4
+ import { Logger } from '../../../utils/logger.js';
4
5
  export default class EnvListCommand extends DeployedStackCommand {
6
+ static summary = 'List environment variables for a deployed function';
7
+ static description = `Displays all environment variables (keys only) configured in a deployed Sanity Function.
8
+
9
+ Use 'functions env add' to set variables or 'functions env remove' to delete them.`;
5
10
  static args = {
6
11
  name: Args.string({ description: 'The name of the Sanity Function', required: true }),
7
12
  };
8
- static description = 'List the environment variables for a Sanity function';
9
13
  static examples = ['<%= config.bin %> <%= command.id %> MyFunction'];
10
14
  async run() {
11
15
  const { success, error } = await functionEnvListCore({
12
16
  bin: this.config.bin,
13
- log: (msg) => this.log(msg),
17
+ log: Logger(this.log.bind(this), this.flags),
14
18
  args: this.args,
15
19
  auth: this.auth,
16
20
  blueprint: this.blueprint,
@@ -1,10 +1,11 @@
1
1
  import { DeployedStackCommand } from '../../../baseCommands.js';
2
2
  export default class EnvRemoveCommand extends DeployedStackCommand<typeof EnvRemoveCommand> {
3
+ static summary: string;
4
+ static description: string;
3
5
  static args: {
4
6
  name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
7
  key: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
6
8
  };
7
- static description: string;
8
9
  static examples: string[];
9
10
  run(): Promise<void>;
10
11
  }
@@ -1,17 +1,21 @@
1
1
  import { Args } from '@oclif/core';
2
2
  import { DeployedStackCommand } from '../../../baseCommands.js';
3
3
  import { functionEnvRemoveCore } from '../../../cores/functions/env/remove.js';
4
+ import { Logger } from '../../../utils/logger.js';
4
5
  export default class EnvRemoveCommand extends DeployedStackCommand {
6
+ static summary = 'Remove an environment variable from a deployed function';
7
+ static description = `Deletes an environment variable from a deployed Sanity Function. The change takes effect on the next function invocation.
8
+
9
+ Use 'functions env list' to see current variables before removing.`;
5
10
  static args = {
6
11
  name: Args.string({ description: 'The name of the Sanity Function', required: true }),
7
12
  key: Args.string({ description: 'The name of the environment variable', required: true }),
8
13
  };
9
- static description = 'Remove an environment variable for a Sanity function';
10
14
  static examples = ['<%= config.bin %> <%= command.id %> MyFunction API_URL'];
11
15
  async run() {
12
16
  const { success, error } = await functionEnvRemoveCore({
13
17
  bin: this.config.bin,
14
- log: (msg) => this.log(msg),
18
+ log: Logger(this.log.bind(this), this.flags),
15
19
  args: this.args,
16
20
  auth: this.auth,
17
21
  blueprint: this.blueprint,
@@ -1,9 +1,10 @@
1
1
  import { DeployedStackCommand } from '../../baseCommands.js';
2
2
  export default class LogsCommand extends DeployedStackCommand<typeof LogsCommand> {
3
+ static summary: string;
4
+ static description: string;
3
5
  static args: {
4
6
  name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
7
  };
6
- static description: string;
7
8
  static examples: string[];
8
9
  static flags: {
9
10
  limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
@@ -1,11 +1,15 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import { DeployedStackCommand } from '../../baseCommands.js';
3
3
  import { functionLogsCore } from '../../cores/functions/logs.js';
4
+ import { Logger } from '../../utils/logger.js';
4
5
  export default class LogsCommand extends DeployedStackCommand {
6
+ static summary = 'Retrieve or delete logs for a Sanity Function';
7
+ static description = `Fetches execution logs from a deployed function, useful for debugging production issues or monitoring activity.
8
+
9
+ Use --watch (-w) to stream logs in real-time. Use --delete to clear all logs for a function (requires confirmation unless --force is specified).`;
5
10
  static args = {
6
11
  name: Args.string({ description: 'The name of the Sanity Function', required: false }),
7
12
  };
8
- static description = 'Retrieve or delete logs for a Sanity Function';
9
13
  static examples = [
10
14
  '<%= config.bin %> <%= command.id %> <name>',
11
15
  '<%= config.bin %> <%= command.id %> <name> --json',
@@ -48,12 +52,11 @@ export default class LogsCommand extends DeployedStackCommand {
48
52
  }),
49
53
  };
50
54
  async run() {
51
- const { name } = this.args;
52
55
  const { success, error } = await functionLogsCore({
53
56
  bin: this.config.bin,
54
- log: (msg) => this.log(msg),
57
+ log: Logger(this.log.bind(this), this.flags),
55
58
  error: (msg, options) => this.error(msg, options),
56
- args: { name },
59
+ args: this.args,
57
60
  flags: this.flags,
58
61
  auth: this.auth,
59
62
  blueprint: this.blueprint,
@@ -1,9 +1,10 @@
1
1
  import { LocalBlueprintCommand } from '../../baseCommands.js';
2
2
  export default class TestCommand extends LocalBlueprintCommand<typeof TestCommand> {
3
+ static summary: string;
4
+ static description: string;
3
5
  static args: {
4
6
  name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
7
  };
6
- static description: string;
7
8
  static examples: string[];
8
9
  static flags: {
9
10
  data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -1,11 +1,15 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import { LocalBlueprintCommand } from '../../baseCommands.js';
3
3
  import { functionTestCore } from '../../cores/functions/test.js';
4
+ import { Logger } from '../../utils/logger.js';
4
5
  export default class TestCommand extends LocalBlueprintCommand {
6
+ static summary = 'Invoke a local Sanity Function';
7
+ static description = `Executes a function locally with the provided payload, simulating how it would run when deployed. Use this to test your function logic before deploying.
8
+
9
+ Provide test data via --data (inline JSON), --file (JSON file), or --document-id (fetch from Sanity). For update events, use the before/after flag pairs to simulate document changes.`;
5
10
  static args = {
6
11
  name: Args.string({ description: 'The name of the Sanity Function', required: false }),
7
12
  };
8
- static description = 'Invoke a local Sanity Function';
9
13
  static examples = [
10
14
  `<%= config.bin %> <%= command.id %> <name> --data '{ "id": 1 }'`,
11
15
  `<%= config.bin %> <%= command.id %> <name> --file 'payload.json'`,
@@ -165,7 +169,7 @@ export default class TestCommand extends LocalBlueprintCommand {
165
169
  }
166
170
  const { success, error } = await functionTestCore({
167
171
  bin: this.config.bin,
168
- log: (msg) => this.log(msg),
172
+ log: Logger(this.log.bind(this), this.flags),
169
173
  error: (msg, options) => this.error(msg, options),
170
174
  args: { ...this.args, name },
171
175
  flags: this.flags,
@@ -4,7 +4,7 @@ import { filePathRelativeToCwd, labeledId, warn } from '../../utils/display/pres
4
4
  import { promptForProject, promptForStack } from '../../utils/display/prompt.js';
5
5
  export async function blueprintConfigCore(options) {
6
6
  const { bin = 'sanity', blueprint, log, token, flags } = options;
7
- const { edit: editConfig = false, 'project-id': flagProjectId, 'organization-id': flagOrganizationId, 'stack-id': flagStackId, verbose: v = false, } = flags;
7
+ const { edit: editConfig = false, 'project-id': flagProjectId, 'organization-id': flagOrganizationId, 'stack-id': flagStackId, verbose: _v = false, } = flags;
8
8
  const providedConfigFlag = [flagProjectId, flagStackId, flagOrganizationId].some(Boolean);
9
9
  const { stackId: configStackId, scopeType: configScopeType, scopeId: configScopeId, blueprintConfig, fileInfo, } = blueprint;
10
10
  const blueprintFilePath = fileInfo.blueprintFilePath;
@@ -17,7 +17,7 @@ export async function blueprintConfigCore(options) {
17
17
  }
18
18
  }
19
19
  if (blueprintConfig)
20
- printConfig({ configLabel: 'Current', log, config: blueprintConfig, v });
20
+ printConfig({ configLabel: 'Current', log, config: blueprintConfig });
21
21
  // passing new config without --edit flag is not allowed
22
22
  if (providedConfigFlag && !editConfig) {
23
23
  log('To update the configuration, use the --edit flag.');
@@ -40,7 +40,7 @@ export async function blueprintConfigCore(options) {
40
40
  configUpdate.organizationId = flagOrganizationId;
41
41
  try {
42
42
  const newConfig = patchConfigFile(blueprintFilePath, configUpdate);
43
- printConfig({ configLabel: 'Updated', log, config: newConfig, v });
43
+ printConfig({ configLabel: 'Updated', log, config: newConfig });
44
44
  return { success: true };
45
45
  }
46
46
  catch {
@@ -54,6 +54,7 @@ export async function blueprintConfigCore(options) {
54
54
  const pickedProject = await promptForProject({
55
55
  token,
56
56
  knownProjectId: configScopeId,
57
+ logger: log,
57
58
  });
58
59
  updatedProjectId = pickedProject.projectId;
59
60
  }
@@ -61,18 +62,18 @@ export async function blueprintConfigCore(options) {
61
62
  return { success: false, error: 'Project ID is required.' };
62
63
  let updatedStackId = flagStackId;
63
64
  if (!updatedStackId) {
64
- const pickedStack = await promptForStack({ projectId: updatedProjectId, token });
65
+ const pickedStack = await promptForStack({ projectId: updatedProjectId, token, logger: log });
65
66
  updatedStackId = pickedStack.stackId;
66
67
  }
67
68
  if (!updatedStackId)
68
69
  return { success: false, error: 'Stack is required.' };
69
70
  try {
70
71
  // update or create config JSON
71
- const newConfig = await writeConfigFile(blueprintFilePath, {
72
+ const newConfig = writeConfigFile(blueprintFilePath, {
72
73
  projectId: updatedProjectId,
73
74
  stackId: updatedStackId,
74
75
  });
75
- printConfig({ configLabel: 'Updated', log, config: newConfig, v });
76
+ printConfig({ configLabel: 'Updated', log, config: newConfig });
76
77
  return { success: true };
77
78
  }
78
79
  catch {
@@ -81,12 +82,11 @@ export async function blueprintConfigCore(options) {
81
82
  }
82
83
  }
83
84
  function printConfig(options) {
84
- const { configLabel, log, config, v = false } = options;
85
+ const { configLabel, log, config } = options;
85
86
  const { projectId, organizationId, stackId, updatedAt } = config;
86
87
  const scopeType = projectId ? 'project' : 'organization';
87
88
  const scopeId = projectId ? projectId : organizationId;
88
- if (v)
89
- log(JSON.stringify(config));
89
+ log.verbose(JSON.stringify(config));
90
90
  log(`${chalk.bold(`${configLabel} configuration:`)}`);
91
91
  log(` Deployment: ${labeledId('stack', stackId)}`);
92
92
  log(` Scoped to: ${labeledId(scopeType, scopeId)}`);
@@ -1,6 +1,5 @@
1
1
  import { setTimeout } from 'node:timers/promises';
2
2
  import chalk from 'chalk';
3
- import ora from 'ora';
4
3
  import { stashAsset } from '../../actions/blueprints/assets.js';
5
4
  import { setupLogStreaming } from '../../actions/blueprints/logs-streaming.js';
6
5
  import { getStack, updateStack } from '../../actions/blueprints/stacks.js';
@@ -8,7 +7,7 @@ import { niceId } from '../../utils/display/presenters.js';
8
7
  import { isLocalFunctionCollection, isLocalFunctionResource } from '../../utils/types.js';
9
8
  export async function blueprintDeployCore(options) {
10
9
  const { bin = 'sanity', log, auth, stackId, scopeType, scopeId, deployedStack, blueprint, flags, } = options;
11
- const { verbose } = flags;
10
+ const { verbose: _verbose } = flags;
12
11
  const noWait = flags['no-wait'] || false;
13
12
  log(`Deploying "${deployedStack.name}" ${niceId(deployedStack.id)}...`);
14
13
  try {
@@ -21,8 +20,8 @@ export async function blueprintDeployCore(options) {
21
20
  if (allFunctionResources.length > 0) {
22
21
  log('Processing function assets...');
23
22
  for (const resource of allFunctionResources) {
24
- const fnSpinner = ora({ text: `Processing ${resource.name}...`, prefixText: ' ' }).start();
25
- const result = await stashAsset({ resource, auth });
23
+ const fnSpinner = log.ora({ text: `Processing ${resource.name}...`, prefixText: ' ' }).start();
24
+ const result = await stashAsset({ resource, auth, logger: log });
26
25
  if (result.success && result.assetId) {
27
26
  resource.src = result.assetId;
28
27
  if (isLocalFunctionCollection(resource)) {
@@ -45,18 +44,16 @@ export async function blueprintDeployCore(options) {
45
44
  fnSpinner.succeed(`${resource.name} ${niceId(result.assetId)}`);
46
45
  log(` Source: ${resource.src}`);
47
46
  }
48
- if (verbose) {
49
- if (result.hash) {
50
- if (result.hash.length > 24) {
51
- log(` Hash: ${result.hash.slice(0, 8)}...${result.hash.slice(-12)}`);
52
- }
53
- else {
54
- log(` Hash: ${result.hash}`);
55
- }
47
+ if (result.hash) {
48
+ if (result.hash.length > 24) {
49
+ log.verbose(` Hash: ${result.hash.slice(0, 8)}...${result.hash.slice(-12)}`);
50
+ }
51
+ else {
52
+ log.verbose(` Hash: ${result.hash}`);
56
53
  }
57
- if (result.exists)
58
- log(' Asset unchanged');
59
54
  }
55
+ if (result.exists)
56
+ log.verbose(' Asset unchanged');
60
57
  }
61
58
  else {
62
59
  const errorMsg = isLocalFunctionCollection(resource)
@@ -67,7 +64,7 @@ export async function blueprintDeployCore(options) {
67
64
  }
68
65
  }
69
66
  }
70
- const spinner = ora('Deploying...').start();
67
+ const spinner = log.ora('Deploying...').start();
71
68
  const isoNow = new Date().toISOString();
72
69
  const { ok: deployOk, stack, error: deployError, } = await updateStack({
73
70
  stackId,
@@ -78,6 +75,7 @@ export async function blueprintDeployCore(options) {
78
75
  document: { resources: validResources },
79
76
  },
80
77
  auth,
78
+ logger: log,
81
79
  });
82
80
  if (!deployOk) {
83
81
  spinner.fail(`${chalk.red('Failed')} to update Stack deployment`);
@@ -99,7 +97,7 @@ export async function blueprintDeployCore(options) {
99
97
  log,
100
98
  });
101
99
  while (true) {
102
- const { ok, stack: currentStack } = await getStack({ stackId: stack.id, auth });
100
+ const { ok, stack: currentStack } = await getStack({ stackId: stack.id, auth, logger: log });
103
101
  if (!ok) {
104
102
  if (logStreamCleanup)
105
103
  logStreamCleanup();
@@ -1,7 +1,6 @@
1
1
  import { setTimeout } from 'node:timers/promises';
2
2
  import { confirm } from '@inquirer/prompts';
3
3
  import chalk from 'chalk';
4
- import ora from 'ora';
5
4
  import { setupLogStreaming } from '../../actions/blueprints/logs-streaming.js';
6
5
  import { destroyStack, getStack } from '../../actions/blueprints/stacks.js';
7
6
  import { niceId } from '../../utils/display/presenters.js';
@@ -26,6 +25,7 @@ export async function blueprintDestroyCore(options) {
26
25
  const { ok, error, stack } = await destroyStack({
27
26
  stackId: flagStackId,
28
27
  auth: { token, scopeType, scopeId },
28
+ logger: log,
29
29
  });
30
30
  if (!ok)
31
31
  return { success: false, error: error || 'Failed to destroy Stack deployment' };
@@ -39,20 +39,20 @@ export async function blueprintDestroyCore(options) {
39
39
  let stack;
40
40
  try {
41
41
  if (flagStackId) {
42
- const flagStack = await getStack({ stackId: flagStackId, auth });
42
+ const flagStack = await getStack({ stackId: flagStackId, auth, logger: log });
43
43
  if (!flagStack.ok)
44
44
  return { success: false, error: flagStack.error || 'Failed to get Stack' };
45
45
  stack = flagStack.stack;
46
46
  }
47
47
  else if (stackId) {
48
- const blueprintStack = await getStack({ stackId, auth });
48
+ const blueprintStack = await getStack({ stackId, auth, logger: log });
49
49
  if (!blueprintStack.ok)
50
50
  return { success: false, error: blueprintStack.error || 'Failed to get Stack' };
51
51
  stack = blueprintStack.stack;
52
52
  }
53
53
  if (!stack)
54
54
  return { success: false, error: 'Stack deployment not found' };
55
- const destroySpinner = ora({
55
+ const destroySpinner = log.ora({
56
56
  text: `Destroying Stack deployment "${chalk.bold(stack.name)}" ${niceId(stack.id)}...`,
57
57
  color: 'red',
58
58
  });
@@ -79,7 +79,7 @@ export async function blueprintDestroyCore(options) {
79
79
  destroySpinner.start();
80
80
  }
81
81
  const isoNow = new Date().toISOString();
82
- const { ok, error } = await destroyStack({ stackId: stack.id, auth });
82
+ const { ok, error } = await destroyStack({ stackId: stack.id, auth, logger: log });
83
83
  if (!ok) {
84
84
  destroySpinner.fail('Failed to destroy Stack deployment');
85
85
  return { success: false, error: error || 'Failed to destroy Stack deployment' };
@@ -99,7 +99,7 @@ export async function blueprintDestroyCore(options) {
99
99
  log,
100
100
  });
101
101
  while (true) {
102
- const { ok, stack: currentStack } = await getStack({ stackId: stack.id, auth });
102
+ const { ok, stack: currentStack } = await getStack({ stackId: stack.id, auth, logger: log });
103
103
  const operation = currentStack?.recentOperation;
104
104
  if (!ok || !operation || operation?.status === 'COMPLETED') {
105
105
  // Operation is also marked destroyed when stack is deleted;
@@ -4,6 +4,7 @@ import { findBlueprintFile, readLocalBlueprint, } from '../../actions/blueprints
4
4
  import { getStack } from '../../actions/blueprints/stacks.js';
5
5
  import config from '../../config.js';
6
6
  import { capitalize, check, filePathRelativeToCwd, indent, niceId, severe, unsure, } from '../../utils/display/presenters.js';
7
+ import { createTracedFetch } from '../../utils/traced-fetch.js';
7
8
  import { validTokenOrErrorMessage } from '../../utils/validated-token.js';
8
9
  import { blueprintConfigCore } from './config.js';
9
10
  const diagLookup = {
@@ -20,24 +21,23 @@ const diagLookup = {
20
21
  export async function blueprintDoctorCore(options) {
21
22
  const { bin, log, token, flags: { verbose: v, path: p, fix }, } = options;
22
23
  const yikes = (s) => {
23
- log(chalk.bgRedBright.whiteBright.bold(` ${s} `));
24
+ log.error(chalk.bgRedBright.whiteBright.bold(` ${s} `));
24
25
  };
25
26
  const here = cwd();
26
27
  const path = p || here;
27
28
  let tokenOrError;
28
- if (v)
29
- log(`Checking ${filePathRelativeToCwd(path)}`);
29
+ log.verbose(`Checking ${filePathRelativeToCwd(path)}`);
30
30
  // 3 states: null == unknown, true == good, false == bad
31
31
  const diagnostics = {};
32
32
  for (const key in diagLookup) {
33
33
  diagnostics[key] = null;
34
34
  }
35
35
  // ONLINE
36
+ const fetchFn = createTracedFetch(log);
36
37
  try {
37
- const res = await fetch(config.apiUrl);
38
+ const res = await fetchFn(config.apiUrl);
38
39
  if (res.ok) {
39
- if (v)
40
- log(`Successfully pinged ${config.apiUrl}`);
40
+ log.verbose(`Successfully pinged ${config.apiUrl}`);
41
41
  diagnostics.online = res.ok;
42
42
  }
43
43
  else {
@@ -51,7 +51,7 @@ export async function blueprintDoctorCore(options) {
51
51
  // TOKEN
52
52
  if (token) {
53
53
  diagnostics.tokenPresent = true;
54
- tokenOrError = await validTokenOrErrorMessage(token);
54
+ tokenOrError = await validTokenOrErrorMessage(log, token);
55
55
  if (tokenOrError.ok) {
56
56
  diagnostics.tokenValid = true;
57
57
  }
@@ -66,8 +66,7 @@ export async function blueprintDoctorCore(options) {
66
66
  // BLUEPRINT file
67
67
  const blueprintFile = findBlueprintFile(path);
68
68
  if (blueprintFile?.blueprintFilePath) {
69
- if (v)
70
- log(`Found blueprint file at ${blueprintFile.blueprintFilePath.replace(here, '.')}`);
69
+ log.verbose(`Found blueprint file at ${blueprintFile.blueprintFilePath.replace(here, '.')}`);
71
70
  diagnostics.blueprintPresent = true;
72
71
  }
73
72
  else {
@@ -75,21 +74,18 @@ export async function blueprintDoctorCore(options) {
75
74
  }
76
75
  let blueprint;
77
76
  try {
78
- blueprint = await readLocalBlueprint(path);
77
+ blueprint = await readLocalBlueprint(log, path);
79
78
  if (blueprint.errors.length === 0) {
80
- if (v)
81
- log(`Blueprint has no errors`);
79
+ log.verbose(`Blueprint has no errors`);
82
80
  diagnostics.blueprintValid = true;
83
81
  }
84
82
  else {
85
- if (v)
86
- log(`Blueprint errors: \n${blueprint.errors.join('\n ')}`);
83
+ log.verbose(`Blueprint errors: \n${blueprint.errors.join('\n ')}`);
87
84
  diagnostics.blueprintValid = false;
88
85
  }
89
86
  }
90
87
  catch {
91
- if (v)
92
- yikes(`Unable to read blueprint`);
88
+ yikes(`Unable to read blueprint`);
93
89
  diagnostics.blueprintValid = false;
94
90
  }
95
91
  if (blueprint) {
@@ -97,18 +93,15 @@ export async function blueprintDoctorCore(options) {
97
93
  const configPath = blueprintConfig?.configPath;
98
94
  // CONFIG file
99
95
  if (configPath) {
100
- if (v)
101
- log(`Found config file at ${configPath.replace(here, '.')}`);
96
+ log.verbose(`Found config file at ${configPath.replace(here, '.')}`);
102
97
  diagnostics.configFilePresent = true;
103
98
  if (scopeType && scopeId && stackId) {
104
99
  diagnostics.configFileValid = true;
105
- if (v) {
106
- const configOutput = [
107
- `${capitalize(scopeType)}: ${niceId(scopeId)}`,
108
- `Deployment: ${niceId(stackId)}`,
109
- ].join('\n');
110
- log(indent(configOutput));
111
- }
100
+ const configOutput = [
101
+ `${capitalize(scopeType)}: ${niceId(scopeId)}`,
102
+ `Deployment: ${niceId(stackId)}`,
103
+ ].join('\n');
104
+ log.verbose(indent(configOutput));
112
105
  }
113
106
  else {
114
107
  diagnostics.configFileValid = false;
@@ -122,10 +115,10 @@ export async function blueprintDoctorCore(options) {
122
115
  const stackResponse = await getStack({
123
116
  auth: { token, scopeType: 'project', scopeId: projectId },
124
117
  stackId,
118
+ logger: log,
125
119
  });
126
120
  if (stackResponse.ok) {
127
- if (v)
128
- log(`Deployment "Stack" ${niceId(stackId)} ready`);
121
+ log.verbose(`Deployment "Stack" ${niceId(stackId)} ready`);
129
122
  diagnostics.stackReady = true;
130
123
  diagnostics.userHasAccess = true;
131
124
  }
@@ -8,9 +8,9 @@ export async function blueprintInfoCore(options) {
8
8
  const targetStackId = flagStackId || stackId;
9
9
  let stack = deployedStack;
10
10
  if (flagStackId) {
11
- const existingStackResponse = await getStack({ stackId: targetStackId, auth });
11
+ const existingStackResponse = await getStack({ stackId: targetStackId, auth, logger: log });
12
12
  if (!existingStackResponse.ok) {
13
- log(`Could not retrieve Stack deployment info for ${niceId(targetStackId)}`);
13
+ log.error(`Could not retrieve Stack deployment info for ${niceId(targetStackId)}`);
14
14
  return {
15
15
  success: false,
16
16
  error: existingStackResponse.error || 'Failed to retrieve Stack deployment',
@@ -25,7 +25,7 @@ export async function blueprintInfoCore(options) {
25
25
  }
26
26
  catch (error) {
27
27
  const errorMessage = error instanceof Error ? error.message : String(error);
28
- log(`Error: ${errorMessage}`);
28
+ log.error(`Error: ${errorMessage}`);
29
29
  return {
30
30
  success: false,
31
31
  error: errorMessage,
@@ -33,13 +33,13 @@ export declare function resolveScopeAndStack(params: {
33
33
  organizationId: string | undefined;
34
34
  stackId: string | undefined;
35
35
  stackName: string | undefined;
36
- log: (message: string) => void;
36
+ log: CoreConfig['log'];
37
37
  token: string;
38
38
  }): Promise<ResolvedScope>;
39
39
  export declare function determineBlueprintExtension(params: {
40
40
  requestedType: string | undefined;
41
41
  blueprintDir: string;
42
- log: (message: string) => void;
42
+ log: CoreConfig['log'];
43
43
  }): Promise<string>;
44
44
  export declare function createBlueprintFiles(params: {
45
45
  blueprintDir: string;
@@ -49,6 +49,6 @@ export declare function createBlueprintFiles(params: {
49
49
  scopeId: string;
50
50
  stackId: string | undefined;
51
51
  bin: string;
52
- log: (message: string) => void;
52
+ log: CoreConfig['log'];
53
53
  }): Promise<CoreResult>;
54
54
  export {};
@@ -33,7 +33,7 @@ export async function blueprintInitCore(options) {
33
33
  // look for existing blueprint file and maybe re-configure it
34
34
  const existingBlueprintFile = findBlueprintFile(blueprintDir);
35
35
  if (existingBlueprintFile) {
36
- log(warn(`Existing Blueprint found: ${filePathRelativeToCwd(existingBlueprintFile.blueprintFilePath)}`));
36
+ log.warn(warn(`Existing Blueprint found: ${filePathRelativeToCwd(existingBlueprintFile.blueprintFilePath)}`));
37
37
  if (flagExample) {
38
38
  return {
39
39
  success: false,
@@ -54,7 +54,7 @@ export async function blueprintInitCore(options) {
54
54
  if (!overwrite)
55
55
  return { success: false, error: 'Initialization cancelled.' };
56
56
  }
57
- const existingBlueprint = await readLocalBlueprint(existingBlueprintFile.blueprintFilePath);
57
+ const existingBlueprint = await readLocalBlueprint(log, existingBlueprintFile.blueprintFilePath);
58
58
  return blueprintConfigCore({
59
59
  blueprint: existingBlueprint,
60
60
  bin,
@@ -121,16 +121,21 @@ export function validateFlags(flags) {
121
121
  async function handleExampleInitialization(options) {
122
122
  const { exampleName, blueprintDir, userProvidedDirName, projectId, token, log } = options;
123
123
  log(warn(`Example feature is experimental. Setting up "${exampleName}"...`));
124
- const exampleExists = await verifyExampleExists({ type: 'blueprint', name: exampleName });
124
+ const exampleExists = await verifyExampleExists({
125
+ type: 'blueprint',
126
+ name: exampleName,
127
+ logger: log,
128
+ });
125
129
  if (!exampleExists) {
126
130
  return { success: false, error: `Blueprint example "${exampleName}" does not exist.` };
127
131
  }
128
- const resolvedProjectId = projectId || (await promptForProject({ token })).projectId;
132
+ const resolvedProjectId = projectId || (await promptForProject({ token, logger: log })).projectId;
129
133
  const stack = await createEmptyStack({
130
134
  token,
131
135
  scopeType: SCOPE_PROJECT,
132
136
  scopeId: resolvedProjectId,
133
137
  name: `example-${exampleName}`,
138
+ logger: log,
134
139
  });
135
140
  const exampleDir = userProvidedDirName || join(blueprintDir, exampleName);
136
141
  if (existsSync(exampleDir)) {
@@ -140,6 +145,7 @@ async function handleExampleInitialization(options) {
140
145
  exampleType: 'blueprint',
141
146
  exampleName,
142
147
  dir: exampleDir,
148
+ logger: log,
143
149
  });
144
150
  if (!addedExample) {
145
151
  return { success: false, error: `Unable to download example "${exampleName}"` };
@@ -184,18 +190,19 @@ export async function resolveScopeAndStack(params) {
184
190
  scopeType,
185
191
  scopeId,
186
192
  name: stackName,
193
+ logger: log,
187
194
  });
188
195
  resolvedStackId = stack.id;
189
196
  }
190
197
  if (!scopeId) {
191
198
  log('\nBlueprints are associated with a Sanity Project. Please select one:');
192
- const pickedProject = await promptForProject({ token });
199
+ const pickedProject = await promptForProject({ token, logger: log });
193
200
  scopeType = SCOPE_PROJECT;
194
201
  scopeId = pickedProject.projectId;
195
202
  }
196
203
  if (!resolvedStackId) {
197
204
  log('\nBlueprints are deployed to a "Stack".');
198
- const { stackId } = await promptForStack({ projectId: scopeId, token });
205
+ const { stackId } = await promptForStack({ projectId: scopeId, token, logger: log });
199
206
  resolvedStackId = stackId;
200
207
  }
201
208
  return {
@@ -252,11 +259,11 @@ export async function createBlueprintFiles(params) {
252
259
  if (blueprintExtension !== 'json') {
253
260
  const blueprintsPackage = '@sanity/blueprints';
254
261
  try {
255
- await writeOrUpdateNodeDependency(blueprintFilePath, blueprintsPackage);
262
+ await writeOrUpdateNodeDependency(blueprintFilePath, blueprintsPackage, log);
256
263
  log(check(`${chalk.bold('Added dependency:')} ${blueprintsPackage}`));
257
264
  }
258
265
  catch {
259
- log(warn(`Unable to add ${blueprintsPackage} to your project.`));
266
+ log.warn(warn(`Unable to add ${blueprintsPackage} to your project.`));
260
267
  }
261
268
  }
262
269
  const nextStepParts = [];