@sanity/runtime-cli 14.7.1 → 14.8.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 (81) hide show
  1. package/README.md +140 -97
  2. package/dist/actions/blueprints/assets.d.ts +4 -3
  3. package/dist/actions/blueprints/assets.js +69 -101
  4. package/dist/actions/blueprints/blueprint.d.ts +2 -2
  5. package/dist/actions/blueprints/blueprint.js +1 -8
  6. package/dist/actions/blueprints/config.d.ts +2 -2
  7. package/dist/actions/blueprints/logs-streaming.d.ts +2 -2
  8. package/dist/actions/blueprints/logs.d.ts +2 -4
  9. package/dist/actions/blueprints/resources.d.ts +1 -1
  10. package/dist/actions/blueprints/stacks.d.ts +15 -25
  11. package/dist/actions/functions/dev.d.ts +1 -1
  12. package/dist/actions/functions/env/list.d.ts +1 -1
  13. package/dist/actions/functions/env/remove.d.ts +1 -1
  14. package/dist/actions/functions/env/update.d.ts +1 -1
  15. package/dist/actions/functions/logs.d.ts +3 -3
  16. package/dist/actions/node.d.ts +1 -1
  17. package/dist/actions/sanity/examples.d.ts +2 -2
  18. package/dist/actions/sanity/projects.d.ts +7 -13
  19. package/dist/baseCommands.js +2 -4
  20. package/dist/commands/blueprints/config.d.ts +1 -1
  21. package/dist/commands/blueprints/config.js +2 -1
  22. package/dist/commands/blueprints/deploy.d.ts +1 -1
  23. package/dist/commands/blueprints/deploy.js +2 -1
  24. package/dist/commands/blueprints/destroy.d.ts +1 -1
  25. package/dist/commands/blueprints/destroy.js +2 -1
  26. package/dist/commands/blueprints/doctor.js +2 -2
  27. package/dist/commands/blueprints/info.d.ts +1 -1
  28. package/dist/commands/blueprints/info.js +2 -1
  29. package/dist/commands/blueprints/plan.d.ts +1 -1
  30. package/dist/commands/blueprints/plan.js +2 -1
  31. package/dist/commands/blueprints/promote.js +2 -2
  32. package/dist/commands/blueprints/stacks.d.ts +1 -1
  33. package/dist/commands/blueprints/stacks.js +2 -1
  34. package/dist/commands/functions/build.d.ts +1 -1
  35. package/dist/commands/functions/build.js +2 -1
  36. package/dist/commands/functions/env/add.d.ts +1 -1
  37. package/dist/commands/functions/env/add.js +2 -1
  38. package/dist/commands/functions/env/list.d.ts +1 -1
  39. package/dist/commands/functions/env/list.js +2 -1
  40. package/dist/commands/functions/env/remove.d.ts +1 -1
  41. package/dist/commands/functions/env/remove.js +2 -1
  42. package/dist/commands/functions/logs.d.ts +0 -1
  43. package/dist/commands/functions/logs.js +0 -5
  44. package/dist/commands/functions/test.d.ts +1 -1
  45. package/dist/commands/functions/test.js +2 -1
  46. package/dist/cores/blueprints/config.js +5 -5
  47. package/dist/cores/blueprints/deploy.js +62 -74
  48. package/dist/cores/blueprints/destroy.js +3 -3
  49. package/dist/cores/blueprints/doctor.js +5 -1
  50. package/dist/cores/blueprints/info.js +1 -1
  51. package/dist/cores/blueprints/init.d.ts +4 -3
  52. package/dist/cores/blueprints/plan.js +7 -1
  53. package/dist/cores/blueprints/promote.js +4 -1
  54. package/dist/cores/blueprints/stacks.js +6 -2
  55. package/dist/cores/functions/build.js +2 -2
  56. package/dist/cores/functions/env/add.js +1 -1
  57. package/dist/cores/functions/env/list.js +1 -1
  58. package/dist/cores/functions/env/remove.js +1 -1
  59. package/dist/cores/functions/test.js +4 -4
  60. package/dist/cores/index.d.ts +9 -2
  61. package/dist/cores/index.js +3 -2
  62. package/dist/server/app.d.ts +1 -1
  63. package/dist/server/handlers/invoke.d.ts +1 -1
  64. package/dist/utils/display/prompt.d.ts +2 -2
  65. package/dist/utils/display/prompt.js +1 -1
  66. package/dist/utils/functions/detect-native-modules.js +4 -1
  67. package/dist/utils/functions/fetch-document.d.ts +2 -2
  68. package/dist/utils/functions/prepare-asset.d.ts +2 -7
  69. package/dist/utils/functions/prepare-asset.js +2 -2
  70. package/dist/utils/logger.d.ts +2 -0
  71. package/dist/utils/logger.js +2 -0
  72. package/dist/utils/other/github.d.ts +1 -1
  73. package/dist/utils/other/npmjs.d.ts +1 -1
  74. package/dist/utils/traced-fetch.d.ts +1 -1
  75. package/dist/utils/types.d.ts +16 -2
  76. package/dist/utils/types.js +5 -4
  77. package/dist/utils/validate/resource.d.ts +0 -3
  78. package/dist/utils/validate/resource.js +0 -270
  79. package/dist/utils/validated-token.d.ts +2 -2
  80. package/oclif.manifest.json +20 -58
  81. package/package.json +2 -2
@@ -32,9 +32,9 @@ Run this command when encountering errors with other Blueprint commands. Use --f
32
32
  validateResources: this.flags['validate-resources'],
33
33
  flags: this.flags,
34
34
  });
35
- const { success, error } = result;
35
+ const { success, error, json } = result;
36
36
  if (!success)
37
37
  this.error(error);
38
- return result.data;
38
+ return json;
39
39
  }
40
40
  }
@@ -6,5 +6,5 @@ export default class InfoCommand extends DeployedStackCommand<typeof InfoCommand
6
6
  static flags: {
7
7
  stack: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
8
  };
9
- run(): Promise<void>;
9
+ run(): Promise<Record<string, unknown> | undefined>;
10
10
  }
@@ -20,7 +20,7 @@ Run 'blueprints stacks' to see all available Stacks in your project or organizat
20
20
  }),
21
21
  };
22
22
  async run() {
23
- const { success, error } = await blueprintInfoCore({
23
+ const { success, error, json } = await blueprintInfoCore({
24
24
  bin: this.config.bin,
25
25
  log: Logger(this.log.bind(this), this.flags),
26
26
  stackId: this.stackId,
@@ -30,5 +30,6 @@ Run 'blueprints stacks' to see all available Stacks in your project or organizat
30
30
  });
31
31
  if (!success)
32
32
  this.error(error);
33
+ return json;
33
34
  }
34
35
  }
@@ -6,5 +6,5 @@ export default class PlanCommand extends LocalBlueprintCommand<typeof PlanComman
6
6
  static flags: {
7
7
  stack: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
8
  };
9
- run(): Promise<void>;
9
+ run(): Promise<Record<string, unknown> | undefined>;
10
10
  }
@@ -11,7 +11,7 @@ Run 'blueprints plan' after making local changes to your Blueprint manifest to v
11
11
  stack: unhide(stackFlag),
12
12
  };
13
13
  async run() {
14
- const { success, error } = await blueprintPlanCore({
14
+ const { success, error, json } = await blueprintPlanCore({
15
15
  bin: this.config.bin,
16
16
  log: Logger(this.log.bind(this), this.flags),
17
17
  token: this.sanityToken,
@@ -21,5 +21,6 @@ Run 'blueprints plan' after making local changes to your Blueprint manifest to v
21
21
  });
22
22
  if (!success)
23
23
  this.error(error);
24
+ return json;
24
25
  }
25
26
  }
@@ -25,7 +25,7 @@ export default class PromoteCommand extends DeployedStackCommand {
25
25
  }),
26
26
  };
27
27
  async run() {
28
- const { success, error, data } = await blueprintPromoteCore({
28
+ const { success, error, json } = await blueprintPromoteCore({
29
29
  bin: this.config.bin,
30
30
  log: Logger(this.log.bind(this), this.flags),
31
31
  token: this.sanityToken,
@@ -40,6 +40,6 @@ export default class PromoteCommand extends DeployedStackCommand {
40
40
  });
41
41
  if (!success)
42
42
  this.error(error);
43
- return data;
43
+ return json;
44
44
  }
45
45
  }
@@ -7,5 +7,5 @@ export default class StacksCommand extends LocalBlueprintCommand<typeof StacksCo
7
7
  'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
8
  'organization-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  };
10
- run(): Promise<void>;
10
+ run(): Promise<Record<string, unknown> | undefined>;
11
11
  }
@@ -26,7 +26,7 @@ Use this to discover existing Stacks you can scope a local Blueprint to (using '
26
26
  }),
27
27
  };
28
28
  async run() {
29
- const { success, error } = await blueprintStacksCore({
29
+ const { success, error, json } = await blueprintStacksCore({
30
30
  bin: this.config.bin,
31
31
  log: Logger(this.log.bind(this), this.flags),
32
32
  token: this.sanityToken,
@@ -36,5 +36,6 @@ Use this to discover existing Stacks you can scope a local Blueprint to (using '
36
36
  });
37
37
  if (!success)
38
38
  this.error(error);
39
+ return json;
39
40
  }
40
41
  }
@@ -9,5 +9,5 @@ export default class BuildCommand extends LocalBlueprintCommand<typeof BuildComm
9
9
  'fn-installer': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
10
  'out-dir': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  };
12
- run(): Promise<void>;
12
+ run(): Promise<Record<string, unknown> | undefined>;
13
13
  }
@@ -19,7 +19,7 @@ export default class BuildCommand extends LocalBlueprintCommand {
19
19
  'out-dir': Flags.string({ char: 'o', description: 'Output directory for zip files' }),
20
20
  };
21
21
  async run() {
22
- const { success, error } = await functionBuildCore({
22
+ const { success, error, json } = await functionBuildCore({
23
23
  bin: this.config.bin,
24
24
  log: Logger(this.log.bind(this), this.flags),
25
25
  args: { name: this.args.name },
@@ -29,5 +29,6 @@ export default class BuildCommand extends LocalBlueprintCommand {
29
29
  });
30
30
  if (!success)
31
31
  this.error(error);
32
+ return json;
32
33
  }
33
34
  }
@@ -8,5 +8,5 @@ export default class EnvAddCommand extends DeployedStackCommand<typeof EnvAddCom
8
8
  value: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
9
9
  };
10
10
  static examples: string[];
11
- run(): Promise<void>;
11
+ run(): Promise<Record<string, unknown> | undefined>;
12
12
  }
@@ -16,7 +16,7 @@ Environment variables are useful for API keys, configuration values, and other s
16
16
  '<%= config.bin %> <%= command.id %> MyFunction API_URL https://api.example.com/',
17
17
  ];
18
18
  async run() {
19
- const { success, error } = await functionEnvAddCore({
19
+ const { success, error, json } = await functionEnvAddCore({
20
20
  bin: this.config.bin,
21
21
  log: Logger(this.log.bind(this), this.flags),
22
22
  args: this.args,
@@ -31,5 +31,6 @@ Environment variables are useful for API keys, configuration values, and other s
31
31
  });
32
32
  if (!success)
33
33
  this.error(error);
34
+ return json;
34
35
  }
35
36
  }
@@ -6,5 +6,5 @@ export default class EnvListCommand extends DeployedStackCommand<typeof EnvListC
6
6
  name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
7
  };
8
8
  static examples: string[];
9
- run(): Promise<void>;
9
+ run(): Promise<Record<string, unknown> | undefined>;
10
10
  }
@@ -12,7 +12,7 @@ Use 'functions env add' to set variables or 'functions env remove' to delete the
12
12
  };
13
13
  static examples = ['<%= config.bin %> <%= command.id %> MyFunction'];
14
14
  async run() {
15
- const { success, error } = await functionEnvListCore({
15
+ const { success, error, json } = await functionEnvListCore({
16
16
  bin: this.config.bin,
17
17
  log: Logger(this.log.bind(this), this.flags),
18
18
  args: this.args,
@@ -27,5 +27,6 @@ Use 'functions env add' to set variables or 'functions env remove' to delete the
27
27
  });
28
28
  if (!success)
29
29
  this.error(error);
30
+ return json;
30
31
  }
31
32
  }
@@ -7,5 +7,5 @@ export default class EnvRemoveCommand extends DeployedStackCommand<typeof EnvRem
7
7
  key: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
8
8
  };
9
9
  static examples: string[];
10
- run(): Promise<void>;
10
+ run(): Promise<Record<string, unknown> | undefined>;
11
11
  }
@@ -13,7 +13,7 @@ Use 'functions env list' to see current variables before removing.`;
13
13
  };
14
14
  static examples = ['<%= config.bin %> <%= command.id %> MyFunction API_URL'];
15
15
  async run() {
16
- const { success, error } = await functionEnvRemoveCore({
16
+ const { success, error, json } = await functionEnvRemoveCore({
17
17
  bin: this.config.bin,
18
18
  log: Logger(this.log.bind(this), this.flags),
19
19
  args: this.args,
@@ -28,5 +28,6 @@ Use 'functions env list' to see current variables before removing.`;
28
28
  });
29
29
  if (!success)
30
30
  this.error(error);
31
+ return json;
31
32
  }
32
33
  }
@@ -9,7 +9,6 @@ export default class LogsCommand extends DeployedStackCommand<typeof LogsCommand
9
9
  static flags: {
10
10
  stack: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
12
- json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
12
  utc: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
13
  delete: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
14
  force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -24,11 +24,6 @@ Use --watch (-w) to stream logs in real-time. Use --delete to clear all logs for
24
24
  required: false,
25
25
  default: 50,
26
26
  }),
27
- json: Flags.boolean({
28
- char: 'j',
29
- description: 'Return logs in JSON format',
30
- required: false,
31
- }),
32
27
  utc: Flags.boolean({
33
28
  char: 'u',
34
29
  description: 'Show dates in UTC time zone',
@@ -25,5 +25,5 @@ export default class TestCommand extends LocalBlueprintCommand<typeof TestComman
25
25
  'with-user-token': import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
26
  'media-library-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
27
27
  };
28
- run(): Promise<void>;
28
+ run(): Promise<Record<string, unknown> | undefined>;
29
29
  }
@@ -168,7 +168,7 @@ Provide test data via --data (inline JSON), --file (JSON file), or --document-id
168
168
  ' --document-id-before and --document-id-after');
169
169
  }
170
170
  }
171
- const { success, error } = await functionTestCore({
171
+ const { success, error, json } = await functionTestCore({
172
172
  bin: this.config.bin,
173
173
  log: Logger(this.log.bind(this), this.flags),
174
174
  error: (msg, options) => this.error(msg, options),
@@ -180,5 +180,6 @@ Provide test data via --data (inline JSON), --file (JSON file), or --document-id
180
180
  });
181
181
  if (!success)
182
182
  this.error(error);
183
+ return json;
183
184
  }
184
185
  }
@@ -22,11 +22,11 @@ export async function blueprintConfigCore(options) {
22
22
  // passing new config without --edit flag is not allowed
23
23
  if (providedConfigFlag && !editConfig) {
24
24
  log('To update the configuration, use the --edit flag.');
25
- return { success: true };
25
+ return { success: true, json: blueprintConfig ? { config: blueprintConfig } : undefined };
26
26
  }
27
27
  if (!editConfig) {
28
28
  // no edit; return success early
29
- return { success: true };
29
+ return { success: true, json: blueprintConfig ? { config: blueprintConfig } : undefined };
30
30
  }
31
31
  else {
32
32
  if (providedConfigFlag) {
@@ -50,7 +50,7 @@ export async function blueprintConfigCore(options) {
50
50
  try {
51
51
  const newConfig = patchConfigFile(blueprintFilePath, configUpdate);
52
52
  printConfig({ configLabel: 'Updated', log, config: newConfig });
53
- return { success: true };
53
+ return { success: true, json: { config: newConfig } };
54
54
  }
55
55
  catch {
56
56
  // fallback to writeConfigFile if patchConfigFile fails
@@ -58,7 +58,7 @@ export async function blueprintConfigCore(options) {
58
58
  try {
59
59
  const newConfig = writeConfigFile(blueprintFilePath, configUpdate);
60
60
  printConfig({ configLabel: 'Updated', log, config: newConfig });
61
- return { success: true };
61
+ return { success: true, json: { config: newConfig } };
62
62
  }
63
63
  catch {
64
64
  return { success: false, error: 'Unable to update configuration.' };
@@ -95,7 +95,7 @@ export async function blueprintConfigCore(options) {
95
95
  stackId: updatedStackId,
96
96
  });
97
97
  printConfig({ configLabel: 'Updated', log, config: newConfig });
98
- return { success: true };
98
+ return { success: true, json: { config: newConfig } };
99
99
  }
100
100
  catch {
101
101
  return { success: false, error: 'Unable to update configuration!' };
@@ -4,7 +4,7 @@ import { setupLogStreaming } from '../../actions/blueprints/logs-streaming.js';
4
4
  import { getStack, updateStack } from '../../actions/blueprints/stacks.js';
5
5
  import { niceId } from '../../utils/display/presenters.js';
6
6
  import { styleText } from '../../utils/style-text.js';
7
- import { isLocalFunctionCollection, isLocalFunctionResource } from '../../utils/types.js';
7
+ import { isLocalFunctionResource, isStudioResource } from '../../utils/types.js';
8
8
  const DEFAULT_ASSET_TIMEOUT = 60;
9
9
  const assetTimeoutS = Number(process.env.SANITY_ASSET_TIMEOUT) || DEFAULT_ASSET_TIMEOUT;
10
10
  const assetTimeoutMs = assetTimeoutS * 1000;
@@ -30,77 +30,13 @@ export async function blueprintDeployCore(options) {
30
30
  }
31
31
  const { resources } = blueprint.parsedBlueprint;
32
32
  const validResources = resources?.filter((r) => r.type) || [];
33
- const functionResources = validResources.filter(isLocalFunctionResource);
34
- const functionCollections = validResources.filter(isLocalFunctionCollection);
35
- const allFunctionResources = [...functionResources, ...functionCollections];
36
- // First stash all function assets
37
- if (allFunctionResources.length > 0) {
38
- log('Processing function assets...');
39
- for (const resource of allFunctionResources) {
40
- const fnSpinner = log.ora({ text: `Processing ${resource.name}...`, prefixText: ' ' }).start();
41
- const warnTimer = setTimeout(() => {
42
- fnSpinner.text = `Still processing ${resource.name}, this can take a moment...`;
43
- }, warnTimeoutMs);
44
- let assetTimeoutTimer;
45
- let result;
46
- try {
47
- result = await Promise.race([
48
- stashAsset({ resource, auth, logger: log, installer }),
49
- new Promise((_, reject) => {
50
- assetTimeoutTimer = setTimeout(() => {
51
- reject(new Error(`Processing ${resource.name} timed out after ${assetTimeoutS}s`));
52
- }, assetTimeoutMs);
53
- }),
54
- ]);
55
- }
56
- catch (err) {
57
- const msg = err instanceof Error ? err.message : String(err);
58
- fnSpinner.fail(msg);
59
- return { success: false, error: msg };
60
- }
61
- finally {
62
- clearTimeout(warnTimer);
63
- clearTimeout(assetTimeoutTimer);
64
- }
65
- if (result.success && result.assetId) {
66
- resource.src = result.assetId;
67
- if (isLocalFunctionCollection(resource)) {
68
- try {
69
- for (const func of resource.functions) {
70
- func.src = func.name;
71
- }
72
- fnSpinner.succeed(`${resource.name} collection ${niceId(result.assetId)} (${resource.functions.length} functions)`);
73
- log(` Functions: ${resource.functions.map((f) => f.name).join(', ')}`);
74
- }
75
- catch (err) {
76
- fnSpinner.fail(`Failed to update function collection ${resource.name}`);
77
- return {
78
- success: false,
79
- error: `Error updating function collection '${resource.name}': ${err instanceof Error ? err.message : String(err)}`,
80
- };
81
- }
82
- }
83
- else {
84
- fnSpinner.succeed(`${resource.name} ${niceId(result.assetId)}`);
85
- log(` Source: ${resource.src}`);
86
- }
87
- if (result.hash) {
88
- if (result.hash.length > 24) {
89
- log.verbose(` Hash: ${result.hash.slice(0, 8)}...${result.hash.slice(-12)}`);
90
- }
91
- else {
92
- log.verbose(` Hash: ${result.hash}`);
93
- }
94
- }
95
- if (result.exists)
96
- log.verbose(' Asset unchanged');
97
- }
98
- else {
99
- const errorMsg = isLocalFunctionCollection(resource)
100
- ? `Failed uploading function collection ${resource.name} (${resource.functions?.length || 0} functions), deploy has stopped`
101
- : `Failed uploading ${resource.name} asset, deploy has stopped`;
102
- fnSpinner.fail(errorMsg);
103
- return { success: false, error: result.error || 'Failed to process function resource' };
33
+ const preDeployResources = validResources.filter(isPreDeployResource);
34
+ if (preDeployResources.length > 0) {
35
+ log('Processing assets...');
36
+ for (const resource of preDeployResources) {
37
+ const preDeployResult = await preDeploy(resource, { auth, installer, log });
38
+ if (preDeployResult.success === false) {
39
+ return preDeployResult;
104
40
  }
105
41
  }
106
42
  }
@@ -125,7 +61,7 @@ export async function blueprintDeployCore(options) {
125
61
  if (noWait) {
126
62
  log(styleText(['bold', 'green'], 'Stack deployment started!'));
127
63
  log(`Use \`npx ${bin} blueprints info\` to check status`);
128
- return { success: true, data: { resources } };
64
+ return { success: true, json: { stackId: stack.id, resources }, data: { resources } };
129
65
  }
130
66
  log(styleText('dim', 'Stack deployment progress:'));
131
67
  let logStreamCleanup = null;
@@ -164,7 +100,7 @@ export async function blueprintDeployCore(options) {
164
100
  if (logStreamCleanup)
165
101
  logStreamCleanup();
166
102
  log(styleText(['bold', 'green'], 'Stack deployment completed!'));
167
- return { success: true, data: { resources } };
103
+ return { success: true, json: { stackId: stack.id, resources }, data: { resources } };
168
104
  }
169
105
  if (!idleMessageShown && Date.now() - lastLogAt > 60_000) {
170
106
  log(`No new activity for 60 seconds. The deployment is still running on Sanity servers.`);
@@ -185,3 +121,55 @@ export async function blueprintDeployCore(options) {
185
121
  return { success: false, error: errorMessage };
186
122
  }
187
123
  }
124
+ function isPreDeployResource(r) {
125
+ return isLocalFunctionResource(r) || isStudioResource(r);
126
+ }
127
+ async function preDeploy(resource, options) {
128
+ const { auth, installer, log } = options;
129
+ const fnSpinner = log.ora({ text: `Processing ${resource.name}...`, prefixText: ' ' }).start();
130
+ const warnTimer = setTimeout(() => {
131
+ fnSpinner.text = `Still processing ${resource.name}, this can take a moment...`;
132
+ }, warnTimeoutMs);
133
+ let assetTimeoutTimer;
134
+ let result;
135
+ try {
136
+ result = await Promise.race([
137
+ stashAsset({ resource, auth, logger: log, installer }),
138
+ new Promise((_, reject) => {
139
+ assetTimeoutTimer = setTimeout(() => {
140
+ reject(new Error(`Processing ${resource.name} timed out after ${assetTimeoutS}s`));
141
+ }, assetTimeoutMs);
142
+ }),
143
+ ]);
144
+ }
145
+ catch (err) {
146
+ const msg = err instanceof Error ? err.message : String(err);
147
+ fnSpinner.fail(msg);
148
+ return { success: false, error: msg };
149
+ }
150
+ finally {
151
+ clearTimeout(warnTimer);
152
+ clearTimeout(assetTimeoutTimer);
153
+ }
154
+ if (result.success && result.assetId) {
155
+ resource.src = result.assetId;
156
+ fnSpinner.succeed(`${resource.name} ${niceId(result.assetId)}`);
157
+ log(` Source: ${resource.src}`);
158
+ if (result.hash) {
159
+ if (result.hash.length > 24) {
160
+ log.verbose(` Hash: ${result.hash.slice(0, 8)}...${result.hash.slice(-12)}`);
161
+ }
162
+ else {
163
+ log.verbose(` Hash: ${result.hash}`);
164
+ }
165
+ }
166
+ if (result.exists)
167
+ log.verbose(' Asset unchanged');
168
+ }
169
+ else {
170
+ const errorMsg = `Failed uploading ${resource.name} asset, deploy has stopped`;
171
+ fnSpinner.fail(errorMsg);
172
+ return { success: false, error: result.error || 'Failed to process asset' };
173
+ }
174
+ return { success: true };
175
+ }
@@ -32,7 +32,7 @@ export async function blueprintDestroyCore(options) {
32
32
  if (!ok)
33
33
  return { success: false, error: error || 'Failed to destroy Stack deployment' };
34
34
  log(`Stack deployment "${stack.name}" ${niceId(stack.id)} destroyed`);
35
- return { success: true };
35
+ return { success: true, json: { stackId: stack.id, stackName: stack.name } };
36
36
  }
37
37
  const { scopeType, scopeId, stackId } = blueprint;
38
38
  if (!scopeType || !scopeId)
@@ -92,7 +92,7 @@ export async function blueprintDestroyCore(options) {
92
92
  destroySpinner.stop().clear();
93
93
  if (noWait) {
94
94
  log(styleText(['bold', 'magenta'], 'Stack destruction started!'));
95
- return { success: true };
95
+ return { success: true, json: { stackId: stack.id, stackName: stack.name } };
96
96
  }
97
97
  log(styleText('dim', 'Stack destruction progress:'));
98
98
  let logStreamCleanup = null;
@@ -117,7 +117,7 @@ export async function blueprintDestroyCore(options) {
117
117
  if (logStreamCleanup)
118
118
  logStreamCleanup();
119
119
  log(styleText(['bold', 'magenta'], 'Stack destruction completed!'));
120
- return { success: true };
120
+ return { success: true, json: { stackId: stack.id, stackName: stack.name } };
121
121
  }
122
122
  if (operation.status === 'FAILED') {
123
123
  if (logStreamCleanup)
@@ -273,7 +273,11 @@ export async function blueprintDoctorCore(options) {
273
273
  log(styleText(['bold', 'green'], 'All checks passed'));
274
274
  if (fix)
275
275
  log(styleText(['bold', 'yellow'], 'Nothing to fix; --fix flag is ignored'));
276
- return { success: true, data: { diagnostics: flatDiagnostics } };
276
+ return {
277
+ success: true,
278
+ json: { diagnostics: flatDiagnostics },
279
+ data: { diagnostics: flatDiagnostics },
280
+ };
277
281
  }
278
282
  if (fix) {
279
283
  if (p) {
@@ -6,7 +6,7 @@ export async function blueprintInfoCore(options) {
6
6
  log(formatStackInfo(deployedStack, true));
7
7
  if (deployedStack.resources)
8
8
  log(formatDeployedResourceTree(deployedStack.resources, verbose));
9
- return { success: true };
9
+ return { success: true, json: { stack: deployedStack } };
10
10
  }
11
11
  catch (error) {
12
12
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -1,3 +1,4 @@
1
+ import type { Logger } from '../../utils/logger.js';
1
2
  import type { ScopeType } from '../../utils/types.js';
2
3
  import type { CoreConfig, CoreResult } from '../index.js';
3
4
  export interface BlueprintInitOptions extends CoreConfig {
@@ -35,13 +36,13 @@ export declare function resolveScopeAndStack(params: {
35
36
  stackId: string | undefined;
36
37
  stackName: string | undefined;
37
38
  knownProjectId?: string;
38
- log: CoreConfig['log'];
39
+ log: Logger;
39
40
  token: string;
40
41
  }): Promise<ResolvedScope>;
41
42
  export declare function determineBlueprintExtension(params: {
42
43
  requestedType: string | undefined;
43
44
  blueprintDir: string;
44
- log: CoreConfig['log'];
45
+ log: Logger;
45
46
  }): Promise<string>;
46
47
  export declare function createBlueprintFiles(params: {
47
48
  blueprintDir: string;
@@ -51,6 +52,6 @@ export declare function createBlueprintFiles(params: {
51
52
  scopeId: string;
52
53
  stackId: string | undefined;
53
54
  bin: string;
54
- log: CoreConfig['log'];
55
+ log: Logger;
55
56
  }): Promise<CoreResult>;
56
57
  export {};
@@ -63,5 +63,11 @@ export async function blueprintPlanCore(options) {
63
63
  else {
64
64
  log(`\n ${styleText('dim', `No significant changes to deploy. Run \`npx ${bin} blueprints deploy\` to apply.`)}`);
65
65
  }
66
- return { success: true };
66
+ return {
67
+ success: true,
68
+ json: {
69
+ resources: parsedBlueprint.resources,
70
+ plan: planResponse.deploymentPlan,
71
+ },
72
+ };
67
73
  }
@@ -21,10 +21,13 @@ export async function blueprintPromoteCore(options) {
21
21
  }
22
22
  }
23
23
  try {
24
+ const spinner = log.ora('Promoting Stack...').start();
24
25
  const { ok, error, stack } = await promoteStack({ stackId, auth, logger: log });
25
26
  if (!ok) {
27
+ spinner.fail('Failed to promote Stack');
26
28
  return { success: false, error: error || 'Failed to promote Stack' };
27
29
  }
30
+ spinner.stop().clear();
28
31
  log(`Stack "${stack.name}" ${niceId(stack.id)} promoted successfully`);
29
32
  const { blueprintFilePath } = blueprint.fileInfo;
30
33
  try {
@@ -41,7 +44,7 @@ export async function blueprintPromoteCore(options) {
41
44
  error: 'Stack promoted successfully but failed to update local Blueprint configuration. No config file found.',
42
45
  };
43
46
  }
44
- return { success: true, data: { stack } };
47
+ return { success: true, json: { stack }, data: { stack } };
45
48
  }
46
49
  catch (error) {
47
50
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -25,16 +25,20 @@ export async function blueprintStacksCore(options) {
25
25
  return { success: false, error: 'Unable to determine scope for Blueprint Stacks' };
26
26
  }
27
27
  try {
28
+ const spinner = log.ora('Fetching Stacks...').start();
28
29
  const { ok, stacks, error } = await listStacks({ token, scopeType, scopeId }, log);
29
- if (!ok)
30
+ if (!ok) {
31
+ spinner.fail('Failed to list Stacks');
30
32
  return { success: false, error: error || 'Failed to list stacks' };
33
+ }
34
+ spinner.stop().clear();
31
35
  if (!stacks || stacks.length === 0) {
32
36
  log('No stacks found');
33
37
  return { success: true };
34
38
  }
35
39
  log(`${styleText('bold', capitalize(scopeType))} ${niceId(scopeId)} ${styleText('bold', 'Stacks')}:\n`);
36
40
  log(formatStacksListing(stacks, blueprintStackId));
37
- return { success: true };
41
+ return { success: true, json: { stacks, scopeType, scopeId } };
38
42
  }
39
43
  catch (error) {
40
44
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -28,7 +28,7 @@ export async function functionBuildCore(options) {
28
28
  for (const resource of functions) {
29
29
  const spinner = log.ora(`Building ${resource.name}...`).start();
30
30
  const prepResult = await prepareAsset({ resource }, { installer });
31
- if (!prepResult.success || !prepResult.outputPath) {
31
+ if (prepResult.success === false) {
32
32
  spinner.fail(`Failed to build ${resource.name}`);
33
33
  errors.push({ name: resource.name, error: prepResult.error ?? 'Unknown error' });
34
34
  continue;
@@ -58,5 +58,5 @@ export async function functionBuildCore(options) {
58
58
  log.warn(`${errors.length} function(s) failed to build`);
59
59
  }
60
60
  log(`\nBuild complete: ${built.length} function(s)`);
61
- return { success: true };
61
+ return { success: true, json: { built, errors, outDir } };
62
62
  }
@@ -17,5 +17,5 @@ export async function functionEnvAddCore(options) {
17
17
  };
18
18
  }
19
19
  spinner.succeed(`Update of ${args.key} succeeded`);
20
- return { success: true };
20
+ return { success: true, json: { name: args.name, key: args.key, value: args.value } };
21
21
  }
@@ -16,5 +16,5 @@ export async function functionEnvListCore(options) {
16
16
  for (const key of result.envvars) {
17
17
  options.log(key);
18
18
  }
19
- return { success: true };
19
+ return { success: true, json: { name: args.name, envvars: result.envvars } };
20
20
  }
@@ -14,5 +14,5 @@ export async function functionEnvRemoveCore(options) {
14
14
  return { success: false, error: result.error || 'Unknown error' };
15
15
  }
16
16
  spinner.succeed(`Removal of ${args.key} succeeded`);
17
- return { success: true };
17
+ return { success: true, json: { name: args.name, key: args.key } };
18
18
  }