@sanity/runtime-cli 12.1.0 → 12.3.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 (56) hide show
  1. package/README.md +20 -19
  2. package/dist/actions/blueprints/assets.d.ts +3 -4
  3. package/dist/actions/blueprints/assets.js +118 -2
  4. package/dist/actions/blueprints/blueprint.d.ts +3 -2
  5. package/dist/actions/blueprints/stacks.d.ts +8 -4
  6. package/dist/actions/blueprints/stacks.js +6 -32
  7. package/dist/commands/blueprints/doctor.d.ts +1 -0
  8. package/dist/commands/blueprints/doctor.js +4 -0
  9. package/dist/commands/functions/dev.d.ts +2 -2
  10. package/dist/commands/functions/dev.js +3 -2
  11. package/dist/constants.d.ts +7 -0
  12. package/dist/constants.js +7 -0
  13. package/dist/cores/blueprints/deploy.js +29 -12
  14. package/dist/cores/blueprints/doctor.d.ts +1 -0
  15. package/dist/cores/blueprints/doctor.js +36 -5
  16. package/dist/cores/blueprints/info.js +2 -2
  17. package/dist/cores/functions/env/add.js +2 -2
  18. package/dist/cores/functions/env/list.js +2 -2
  19. package/dist/cores/functions/env/remove.js +2 -2
  20. package/dist/cores/functions/logs.js +2 -2
  21. package/dist/cores/functions/test.js +31 -23
  22. package/dist/server/app.js +32 -21
  23. package/dist/server/handlers/invoke.d.ts +2 -2
  24. package/dist/server/handlers/invoke.js +2 -2
  25. package/dist/server/static/components/api-base.js +3 -0
  26. package/dist/server/static/components/app.css +120 -95
  27. package/dist/server/static/components/clear-button.js +1 -1
  28. package/dist/server/static/components/console-panel.js +6 -6
  29. package/dist/server/static/components/fetch-button.js +1 -1
  30. package/dist/server/static/components/filter-api-version.js +3 -3
  31. package/dist/server/static/components/filter-document-id.js +5 -5
  32. package/dist/server/static/components/filter-with-token.js +4 -4
  33. package/dist/server/static/components/filters.js +2 -2
  34. package/dist/server/static/components/function-list.js +14 -5
  35. package/dist/server/static/components/help-button.js +4 -1
  36. package/dist/server/static/components/payload-panel.js +9 -9
  37. package/dist/server/static/components/response-panel.js +8 -8
  38. package/dist/server/static/components/rule-panel.js +4 -4
  39. package/dist/server/static/components/run-panel.js +4 -4
  40. package/dist/server/static/components/select-dropdown.js +5 -25
  41. package/dist/server/static/index.html +9 -9
  42. package/dist/server/static/vendor/m-.css +1 -0
  43. package/dist/server/static/vendor/m-.woff2 +0 -0
  44. package/dist/utils/display/blueprints-formatting.d.ts +3 -2
  45. package/dist/utils/display/blueprints-formatting.js +102 -50
  46. package/dist/utils/display/resources-formatting.d.ts +6 -2
  47. package/dist/utils/display/resources-formatting.js +71 -17
  48. package/dist/utils/find-function.d.ts +2 -2
  49. package/dist/utils/find-function.js +9 -2
  50. package/dist/utils/invoke-local.d.ts +2 -2
  51. package/dist/utils/invoke-local.js +27 -16
  52. package/dist/utils/types.d.ts +66 -24
  53. package/dist/utils/types.js +25 -2
  54. package/dist/utils/validate/resource.js +144 -23
  55. package/oclif.manifest.json +14 -1
  56. package/package.json +2 -2
package/README.md CHANGED
@@ -20,7 +20,7 @@ $ npm install -g @sanity/runtime-cli
20
20
  $ sanity-run COMMAND
21
21
  running command...
22
22
  $ sanity-run (--version)
23
- @sanity/runtime-cli/12.1.0 linux-x64 node-v24.11.1
23
+ @sanity/runtime-cli/12.3.0 linux-x64 node-v24.11.1
24
24
  $ sanity-run --help [COMMAND]
25
25
  USAGE
26
26
  $ sanity-run COMMAND
@@ -92,7 +92,7 @@ EXAMPLES
92
92
  $ sanity-run blueprints add function --name my-function --fn-type document-create --fn-type document-update --lang js
93
93
  ```
94
94
 
95
- _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/add.ts)_
95
+ _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/add.ts)_
96
96
 
97
97
  ## `sanity-run blueprints config`
98
98
 
@@ -121,7 +121,7 @@ EXAMPLES
121
121
  $ sanity-run blueprints config --edit --project-id <projectId> --stack-id <stackId>
122
122
  ```
123
123
 
124
- _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/config.ts)_
124
+ _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/config.ts)_
125
125
 
126
126
  ## `sanity-run blueprints deploy`
127
127
 
@@ -143,7 +143,7 @@ EXAMPLES
143
143
  $ sanity-run blueprints deploy --no-wait
144
144
  ```
145
145
 
146
- _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/deploy.ts)_
146
+ _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/deploy.ts)_
147
147
 
148
148
  ## `sanity-run blueprints destroy`
149
149
 
@@ -170,7 +170,7 @@ EXAMPLES
170
170
  $ sanity-run blueprints destroy --stack-id <stackId> --project-id <projectId> --force --no-wait
171
171
  ```
172
172
 
173
- _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/destroy.ts)_
173
+ _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/destroy.ts)_
174
174
 
175
175
  ## `sanity-run blueprints doctor`
176
176
 
@@ -178,9 +178,10 @@ Diagnose potential issues with Blueprint configuration
178
178
 
179
179
  ```
180
180
  USAGE
181
- $ sanity-run blueprints doctor [--verbose] [--path <value>]
181
+ $ sanity-run blueprints doctor [--verbose] [--path <value>] [--fix]
182
182
 
183
183
  FLAGS
184
+ --fix Interactively fix configuration issues
184
185
  --path=<value> Path to the Blueprint configuration file
185
186
  --verbose Provide detailed information about issues
186
187
 
@@ -188,7 +189,7 @@ DESCRIPTION
188
189
  Diagnose potential issues with Blueprint configuration
189
190
  ```
190
191
 
191
- _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/doctor.ts)_
192
+ _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/doctor.ts)_
192
193
 
193
194
  ## `sanity-run blueprints info`
194
195
 
@@ -210,7 +211,7 @@ EXAMPLES
210
211
  $ sanity-run blueprints info --id <stackId>
211
212
  ```
212
213
 
213
- _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/info.ts)_
214
+ _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/info.ts)_
214
215
 
215
216
  ## `sanity-run blueprints init [DIR]`
216
217
 
@@ -250,7 +251,7 @@ EXAMPLES
250
251
  $ sanity-run blueprints init --blueprint-type <json|js|ts> --stack-name <stackName>
251
252
  ```
252
253
 
253
- _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/init.ts)_
254
+ _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/init.ts)_
254
255
 
255
256
  ## `sanity-run blueprints logs`
256
257
 
@@ -272,7 +273,7 @@ EXAMPLES
272
273
  $ sanity-run blueprints logs --watch
273
274
  ```
274
275
 
275
- _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/logs.ts)_
276
+ _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/logs.ts)_
276
277
 
277
278
  ## `sanity-run blueprints plan`
278
279
 
@@ -289,7 +290,7 @@ EXAMPLES
289
290
  $ sanity-run blueprints plan
290
291
  ```
291
292
 
292
- _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/plan.ts)_
293
+ _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/plan.ts)_
293
294
 
294
295
  ## `sanity-run blueprints stacks`
295
296
 
@@ -314,7 +315,7 @@ EXAMPLES
314
315
  $ sanity-run blueprints stacks --organization-id <organizationId>
315
316
  ```
316
317
 
317
- _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/blueprints/stacks.ts)_
318
+ _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/blueprints/stacks.ts)_
318
319
 
319
320
  ## `sanity-run functions add`
320
321
 
@@ -356,7 +357,7 @@ EXAMPLES
356
357
  $ sanity-run functions add --name my-function --type document-create --type document-update --lang js
357
358
  ```
358
359
 
359
- _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/functions/add.ts)_
360
+ _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/functions/add.ts)_
360
361
 
361
362
  ## `sanity-run functions dev`
362
363
 
@@ -379,7 +380,7 @@ EXAMPLES
379
380
  $ sanity-run functions dev --host 127.0.0.1 --port 8974
380
381
  ```
381
382
 
382
- _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/functions/dev.ts)_
383
+ _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/functions/dev.ts)_
383
384
 
384
385
  ## `sanity-run functions env add NAME KEY VALUE`
385
386
 
@@ -401,7 +402,7 @@ EXAMPLES
401
402
  $ sanity-run functions env add MyFunction API_URL https://api.example.com/
402
403
  ```
403
404
 
404
- _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/functions/env/add.ts)_
405
+ _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/functions/env/add.ts)_
405
406
 
406
407
  ## `sanity-run functions env list NAME`
407
408
 
@@ -421,7 +422,7 @@ EXAMPLES
421
422
  $ sanity-run functions env list MyFunction
422
423
  ```
423
424
 
424
- _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/functions/env/list.ts)_
425
+ _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/functions/env/list.ts)_
425
426
 
426
427
  ## `sanity-run functions env remove NAME KEY`
427
428
 
@@ -442,7 +443,7 @@ EXAMPLES
442
443
  $ sanity-run functions env remove MyFunction API_URL
443
444
  ```
444
445
 
445
- _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/functions/env/remove.ts)_
446
+ _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/functions/env/remove.ts)_
446
447
 
447
448
  ## `sanity-run functions logs NAME`
448
449
 
@@ -476,7 +477,7 @@ EXAMPLES
476
477
  $ sanity-run functions logs <name> --delete
477
478
  ```
478
479
 
479
- _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/functions/logs.ts)_
480
+ _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/functions/logs.ts)_
480
481
 
481
482
  ## `sanity-run functions test NAME`
482
483
 
@@ -525,7 +526,7 @@ EXAMPLES
525
526
  $ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
526
527
  ```
527
528
 
528
- _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v12.1.0/src/commands/functions/test.ts)_
529
+ _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v12.3.0/src/commands/functions/test.ts)_
529
530
 
530
531
  ## `sanity-run help [COMMAND]`
531
532
 
@@ -1,16 +1,15 @@
1
1
  import AdmZip from 'adm-zip';
2
- import type { AuthParams, FunctionResource } from '../../utils/types.js';
2
+ import type { AuthParams, CollectionFunction, FunctionResource } from '../../utils/types.js';
3
3
  export declare const ASSET_CHECK_URL: string;
4
4
  export declare const ASSET_STASH_URL: string;
5
5
  export declare function stashAsset({ resource, auth, }: {
6
- resource: FunctionResource;
6
+ resource: FunctionResource | CollectionFunction;
7
7
  auth: AuthParams;
8
8
  }): Promise<{
9
9
  success: boolean;
10
+ assetId?: string;
10
11
  exists?: boolean;
11
12
  hash?: string;
12
- assetId?: string;
13
- outputPath?: string;
14
13
  error?: string;
15
14
  }>;
16
15
  export declare function hashBuffer(buffer: Buffer): string;
@@ -1,5 +1,6 @@
1
1
  import crypto from 'node:crypto';
2
2
  import fs from 'node:fs';
3
+ import os from 'node:os';
3
4
  import path from 'node:path';
4
5
  import { cwd } from 'node:process';
5
6
  import AdmZip from 'adm-zip';
@@ -10,12 +11,68 @@ import { shouldAutoResolveDependencies } from '../../utils/functions/should-auto
10
11
  import { shouldTranspileFunction } from '../../utils/functions/should-transpile.js';
11
12
  import getHeaders from '../../utils/get-headers.js';
12
13
  import { transpileFunction } from '../../utils/transpile/transpile-function.js';
14
+ import { isLocalFunctionCollection } from '../../utils/types.js';
13
15
  const { apiUrl } = config;
14
16
  const ASSETS_URL = `${apiUrl}vX/blueprints/assets`;
15
17
  export const ASSET_CHECK_URL = `${ASSETS_URL}/check`;
16
18
  export const ASSET_STASH_URL = `${ASSETS_URL}/stash`;
17
19
  const MAX_ASSET_SIZE = 209_715_200; // 200 MB in bytes
18
20
  export async function stashAsset({ resource, auth, }) {
21
+ const isCollection = isLocalFunctionCollection(resource);
22
+ const functions = isCollection ? resource.functions : [resource];
23
+ const combinedAsset = [];
24
+ try {
25
+ for (const func of functions) {
26
+ const prepResult = await prepareAsset({ resource: func, auth });
27
+ if (prepResult.success && prepResult.outputPath && prepResult.cleanup) {
28
+ combinedAsset.push({
29
+ name: func.name,
30
+ partAsset: { outputPath: prepResult.outputPath, cleanup: prepResult.cleanup },
31
+ });
32
+ }
33
+ }
34
+ if (combinedAsset.length !== functions.length) {
35
+ const processedNames = new Set(combinedAsset.map((asset) => asset.name));
36
+ const failedFunctions = functions.filter((func) => !processedNames.has(func.name));
37
+ return {
38
+ success: false,
39
+ error: `Failed to prepare ${failedFunctions.length} function(s) in collection: ${failedFunctions.map((f) => f.name).join(', ')}`,
40
+ };
41
+ }
42
+ let result = { success: false };
43
+ if (isCollection) {
44
+ const combinedResult = await combineAssets(combinedAsset);
45
+ if (combinedResult.combinedPath && combinedResult.cleanup) {
46
+ result = await stashSingleAsset({
47
+ outputPath: combinedResult.combinedPath,
48
+ cleanup: combinedResult.cleanup,
49
+ resource: resource,
50
+ auth,
51
+ collectionInfo: {
52
+ name: resource.name,
53
+ functionCount: resource.functions.length,
54
+ },
55
+ });
56
+ }
57
+ else if (combinedResult.error) {
58
+ result = { success: false, error: combinedResult.error };
59
+ }
60
+ }
61
+ else {
62
+ result = await stashSingleAsset({
63
+ outputPath: combinedAsset[0].partAsset.outputPath,
64
+ cleanup: combinedAsset[0].partAsset.cleanup,
65
+ resource: resource,
66
+ auth,
67
+ });
68
+ }
69
+ return result;
70
+ }
71
+ catch (err) {
72
+ return { success: false, error: err instanceof Error ? err.message : `${err}` };
73
+ }
74
+ }
75
+ async function prepareAsset({ resource, }) {
19
76
  if (!resource.src)
20
77
  throw new Error('Resource src is required');
21
78
  let functionPath = path.join(cwd(), resource.src);
@@ -41,7 +98,60 @@ export async function stashAsset({ resource, auth, }) {
41
98
  if (size > MAX_ASSET_SIZE) {
42
99
  throw new Error('Resource is larger than max asset size of 200 MB.');
43
100
  }
44
- const { b64, hash } = await pathToB64ZipHash(functionPath);
101
+ return { success: true, outputPath: functionPath, cleanup };
102
+ }
103
+ catch (err) {
104
+ return { success: false, error: err instanceof Error ? err.message : `${err}` };
105
+ }
106
+ }
107
+ async function combineAssets(allAssets) {
108
+ const combinedPath = path.join(os.tmpdir(), `assets-${Date.now()}`);
109
+ await fs.promises.mkdir(combinedPath, { recursive: true });
110
+ try {
111
+ for (const asset of allAssets) {
112
+ try {
113
+ await fs.promises.mkdir(path.join(combinedPath, asset.name), { recursive: true });
114
+ await fs.promises.cp(asset.partAsset.outputPath, path.join(combinedPath, asset.name), {
115
+ recursive: true,
116
+ });
117
+ await asset.partAsset.cleanup();
118
+ }
119
+ catch (err) {
120
+ // Clean up any partial work
121
+ try {
122
+ await fs.promises.rm(combinedPath, { recursive: true, force: true });
123
+ }
124
+ catch {
125
+ // Ignore cleanup errors
126
+ }
127
+ // Clean up remaining individual assets
128
+ await Promise.allSettled(allAssets.map((a) => a.partAsset.cleanup()));
129
+ return {
130
+ error: `Failed to combine asset for function '${asset.name}': ${err instanceof Error ? err.message : String(err)}`,
131
+ };
132
+ }
133
+ }
134
+ const cleanupCombined = async () => {
135
+ await fs.promises.rm(combinedPath, { recursive: true, force: true });
136
+ };
137
+ return { combinedPath, cleanup: cleanupCombined };
138
+ }
139
+ catch (err) {
140
+ // Clean up any partial work
141
+ try {
142
+ await fs.promises.rm(combinedPath, { recursive: true, force: true });
143
+ }
144
+ catch {
145
+ // Ignore cleanup errors
146
+ }
147
+ // Clean up individual assets that were successfully prepared
148
+ await Promise.allSettled(allAssets.map((asset) => asset.partAsset.cleanup()));
149
+ return { error: err instanceof Error ? err.message : `${err}` };
150
+ }
151
+ }
152
+ async function stashSingleAsset({ outputPath, cleanup, resource, auth, collectionInfo, }) {
153
+ try {
154
+ const { b64, hash } = await pathToB64ZipHash(outputPath);
45
155
  try {
46
156
  const checkResponse = await fetch(`${ASSET_CHECK_URL}/${hash}`, {
47
157
  method: 'GET',
@@ -66,7 +176,13 @@ export async function stashAsset({ resource, auth, }) {
66
176
  if (assetResponse.ok) {
67
177
  return { success: true, assetId: assetJson.id, exists: false, hash };
68
178
  }
69
- return { success: false, error: assetJson.message || 'Unknown error' };
179
+ const contextMsg = collectionInfo
180
+ ? ` (part of collection '${collectionInfo.name}' with ${collectionInfo.functionCount} functions)`
181
+ : '';
182
+ return {
183
+ success: false,
184
+ error: `Failed to stash asset for ${resource.name}${contextMsg}: ${assetJson.message || 'Unknown error'}`,
185
+ };
70
186
  }
71
187
  catch (err) {
72
188
  let error = '';
@@ -1,5 +1,6 @@
1
+ import type { BlueprintResource } from '@sanity/blueprints';
1
2
  import { type Blueprint } from '@sanity/blueprints-parser';
2
- import type { BlueprintParserError, Resource } from '../../utils/types.js';
3
+ import type { BlueprintParserError } from '../../utils/types.js';
3
4
  import { type ScopeType } from '../../utils/types.js';
4
5
  import { type LocatedBlueprintsConfig } from './config.js';
5
6
  declare const SUPPORTED_FILE_EXTENSIONS: readonly [".json", ".js", ".mjs", ".ts"];
@@ -51,7 +52,7 @@ export declare function writeBlueprintToDisk({ blueprintFilePath, jsonContent, }
51
52
  blueprintFilePath: string;
52
53
  jsonContent?: Blueprint;
53
54
  }): string;
54
- export declare function addResourceToBlueprint<T extends Resource>({ blueprintFilePath, resource, }: {
55
+ export declare function addResourceToBlueprint<T extends BlueprintResource>({ blueprintFilePath, resource, }: {
55
56
  blueprintFilePath?: string;
56
57
  resource: T;
57
58
  }): T | undefined;
@@ -1,10 +1,14 @@
1
1
  import type { AuthParams, ScopeType, Stack, StackMutation } from '../../utils/types.js';
2
2
  export declare const stacksUrl: string;
3
- interface ListStacksResponse {
4
- ok: boolean;
5
- error: string | null;
3
+ type ListStacksResponse = {
4
+ ok: true;
5
+ error: null;
6
6
  stacks: Stack[];
7
- }
7
+ } | {
8
+ ok: false;
9
+ error: string;
10
+ stacks: unknown;
11
+ };
8
12
  export declare function listStacks(auth: AuthParams): Promise<ListStacksResponse>;
9
13
  interface GetStackResponse {
10
14
  ok: boolean;
@@ -2,32 +2,6 @@ import config from '../../config.js';
2
2
  import getHeaders from '../../utils/get-headers.js';
3
3
  const { apiUrl } = config;
4
4
  export const stacksUrl = `${apiUrl}vX/blueprints/stacks`;
5
- /** Discriminate between Resource and Resource with parameters */
6
- function hasParameters(obj) {
7
- return (typeof obj === 'object' &&
8
- obj !== null &&
9
- 'parameters' in obj &&
10
- typeof obj.parameters === 'object' &&
11
- obj.parameters !== null);
12
- }
13
- /** Flatten Resource with parameters */
14
- function flattenResource(resource) {
15
- if (hasParameters(resource)) {
16
- const { parameters, ...rest } = resource;
17
- return { ...rest, ...parameters };
18
- }
19
- return resource;
20
- }
21
- /** Flatten a Stack's resources */
22
- function flattenStackResources(stack) {
23
- if (stack && Array.isArray(stack.resources)) {
24
- return {
25
- ...stack,
26
- resources: stack.resources.map(flattenResource),
27
- };
28
- }
29
- return stack;
30
- }
31
5
  export async function listStacks(auth) {
32
6
  const response = await fetch(stacksUrl, {
33
7
  method: 'GET',
@@ -37,7 +11,7 @@ export async function listStacks(auth) {
37
11
  return {
38
12
  ok: response.ok,
39
13
  error: response.ok ? null : data.message,
40
- stacks: response.ok ? data.map(flattenStackResources) : data,
14
+ stacks: data,
41
15
  };
42
16
  }
43
17
  export async function getStack({ stackId, auth, }) {
@@ -49,7 +23,7 @@ export async function getStack({ stackId, auth, }) {
49
23
  return {
50
24
  ok: response.ok,
51
25
  error: response.ok ? null : data.message,
52
- stack: response.ok ? flattenStackResources(data) : data,
26
+ stack: data,
53
27
  response,
54
28
  };
55
29
  }
@@ -63,7 +37,7 @@ export async function createStack({ stackMutation, auth, }) {
63
37
  return {
64
38
  ok: response.ok,
65
39
  error: response.ok ? null : data.message,
66
- stack: response.ok ? flattenStackResources(data) : data,
40
+ stack: data,
67
41
  };
68
42
  }
69
43
  export async function createEmptyStack({ token, scopeType, scopeId, name, }) {
@@ -80,7 +54,7 @@ export async function createEmptyStack({ token, scopeType, scopeId, name, }) {
80
54
  if (!response.ok) {
81
55
  throw new Error(response.error || 'Failed to create new Stack');
82
56
  }
83
- return flattenStackResources(response.stack);
57
+ return response.stack;
84
58
  }
85
59
  export async function updateStack({ stackId, stackMutation, auth, }) {
86
60
  const response = await fetch(`${stacksUrl}/${stackId}`, {
@@ -92,7 +66,7 @@ export async function updateStack({ stackId, stackMutation, auth, }) {
92
66
  return {
93
67
  ok: response.ok,
94
68
  error: response.ok ? null : data.message,
95
- stack: response.ok ? flattenStackResources(data) : data,
69
+ stack: data,
96
70
  };
97
71
  }
98
72
  export async function destroyStack({ stackId, auth, }) {
@@ -104,6 +78,6 @@ export async function destroyStack({ stackId, auth, }) {
104
78
  return {
105
79
  ok: response.ok,
106
80
  error: response.ok ? null : data.message,
107
- stack: response.ok ? flattenStackResources(data) : data,
81
+ stack: data,
108
82
  };
109
83
  }
@@ -5,6 +5,7 @@ export default class DoctorCommand extends Command {
5
5
  static flags: {
6
6
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
7
  path: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ fix: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
9
  };
9
10
  run(): Promise<void>;
10
11
  }
@@ -12,6 +12,10 @@ export default class DoctorCommand extends Command {
12
12
  path: Flags.string({
13
13
  description: 'Path to the Blueprint configuration file',
14
14
  }),
15
+ fix: Flags.boolean({
16
+ description: 'Interactively fix configuration issues',
17
+ default: false,
18
+ }),
15
19
  };
16
20
  async run() {
17
21
  const { flags } = await this.parse(DoctorCommand);
@@ -1,5 +1,5 @@
1
- import { Command } from '@oclif/core';
2
- export default class DevCommand extends Command {
1
+ import { BlueprintCommand } from '../../baseCommands.js';
2
+ export default class DevCommand extends BlueprintCommand<typeof DevCommand> {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
@@ -1,6 +1,7 @@
1
- import { Command, Flags } from '@oclif/core';
1
+ import { Flags } from '@oclif/core';
2
+ import { BlueprintCommand } from '../../baseCommands.js';
2
3
  import { functionDevCore } from '../../cores/functions/dev.js';
3
- export default class DevCommand extends Command {
4
+ export default class DevCommand extends BlueprintCommand {
4
5
  static description = 'Start the Sanity Function emulator';
5
6
  static examples = ['<%= config.bin %> <%= command.id %> --host 127.0.0.1 --port 8974'];
6
7
  static flags = {
@@ -0,0 +1,7 @@
1
+ export declare const SANITY_ACCESS_ROLE = "sanity.access.role";
2
+ export declare const SANITY_FUNCTION_DOCUMENT = "sanity.function.document";
3
+ export declare const SANITY_FUNCTION_MEDIA_LIBRARY_ASSET = "sanity.function.media-library.asset";
4
+ export declare const SANITY_FUNCTION_SCHEDULE = "sanity.function.cron";
5
+ export declare const SANITY_PROJECT_CORS = "sanity.project.cors";
6
+ export declare const SANITY_PROJECT_DATASET = "sanity.project.dataset";
7
+ export declare const SANITY_PROJECT_WEBHOOK = "sanity.project.webhook";
@@ -0,0 +1,7 @@
1
+ export const SANITY_ACCESS_ROLE = 'sanity.access.role';
2
+ export const SANITY_FUNCTION_DOCUMENT = 'sanity.function.document';
3
+ export const SANITY_FUNCTION_MEDIA_LIBRARY_ASSET = 'sanity.function.media-library.asset';
4
+ export const SANITY_FUNCTION_SCHEDULE = 'sanity.function.cron';
5
+ export const SANITY_PROJECT_CORS = 'sanity.project.cors';
6
+ export const SANITY_PROJECT_DATASET = 'sanity.project.dataset';
7
+ export const SANITY_PROJECT_WEBHOOK = 'sanity.project.webhook';
@@ -14,23 +14,37 @@ export async function blueprintDeployCore(options) {
14
14
  try {
15
15
  const { resources } = blueprint.parsedBlueprint;
16
16
  const validResources = resources?.filter((r) => r.type) || [];
17
- let functionResources = validResources.filter(isLocalFunctionResource);
18
- const experimentalFunctionCollections = validResources.filter(isLocalFunctionCollection);
19
- if (experimentalFunctionCollections.length > 0) {
20
- const allFunctionResources = experimentalFunctionCollections.flatMap((r) => r.functions);
21
- functionResources = [...functionResources, ...allFunctionResources];
22
- }
17
+ const functionResources = validResources.filter(isLocalFunctionResource);
18
+ const functionCollections = validResources.filter(isLocalFunctionCollection);
19
+ const allFunctionResources = [...functionResources, ...functionCollections];
23
20
  // First stash all function assets
24
- if (functionResources.length > 0) {
21
+ if (allFunctionResources.length > 0) {
25
22
  log('Processing function assets...');
26
- for (const resource of functionResources) {
23
+ for (const resource of allFunctionResources) {
27
24
  const fnSpinner = ora({ text: `Processing ${resource.name}...`, prefixText: ' ' }).start();
28
25
  const result = await stashAsset({ resource, auth });
29
26
  if (result.success && result.assetId) {
30
- const src = resource.src;
31
27
  resource.src = result.assetId;
32
- fnSpinner.succeed(`${resource.name} ${niceId(result.assetId)}`);
33
- log(` Source: ${src}`);
28
+ if (isLocalFunctionCollection(resource)) {
29
+ try {
30
+ for (const func of resource.functions) {
31
+ func.src = func.name;
32
+ }
33
+ fnSpinner.succeed(`${resource.name} collection ${niceId(result.assetId)} (${resource.functions.length} functions)`);
34
+ log(` Functions: ${resource.functions.map((f) => f.name).join(', ')}`);
35
+ }
36
+ catch (err) {
37
+ fnSpinner.fail(`Failed to update function collection ${resource.name}`);
38
+ return {
39
+ success: false,
40
+ error: `Error updating function collection '${resource.name}': ${err instanceof Error ? err.message : String(err)}`,
41
+ };
42
+ }
43
+ }
44
+ else {
45
+ fnSpinner.succeed(`${resource.name} ${niceId(result.assetId)}`);
46
+ log(` Source: ${resource.src}`);
47
+ }
34
48
  if (verbose) {
35
49
  if (result.hash) {
36
50
  if (result.hash.length > 24) {
@@ -45,7 +59,10 @@ export async function blueprintDeployCore(options) {
45
59
  }
46
60
  }
47
61
  else {
48
- fnSpinner.fail(`Failed uploading ${resource.name} asset, deploy has stopped`);
62
+ const errorMsg = isLocalFunctionCollection(resource)
63
+ ? `Failed uploading function collection ${resource.name} (${resource.functions?.length || 0} functions), deploy has stopped`
64
+ : `Failed uploading ${resource.name} asset, deploy has stopped`;
65
+ fnSpinner.fail(errorMsg);
49
66
  log(` Error: ${result.error}`);
50
67
  return { success: false, error: result.error || 'Failed to process function resource' };
51
68
  }
@@ -4,6 +4,7 @@ export interface BlueprintDoctorOptions extends CoreConfig {
4
4
  flags: {
5
5
  verbose?: boolean;
6
6
  path?: string;
7
+ fix?: boolean;
7
8
  };
8
9
  }
9
10
  export declare function blueprintDoctorCore(options: BlueprintDoctorOptions): Promise<CoreResult>;