@sanity/runtime-cli 14.11.0 → 14.12.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.
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/14.11.0 linux-x64 node-v24.14.1
23
+ @sanity/runtime-cli/14.12.0 linux-x64 node-v24.14.1
24
24
  $ sanity-run --help [COMMAND]
25
25
  USAGE
26
26
  $ sanity-run COMMAND
@@ -55,9 +55,9 @@ Add a function resource to a Blueprint
55
55
  ```
56
56
  USAGE
57
57
  $ sanity-run blueprints add TYPE [--json] [--validate-resources] [--example <value> | -n <value> | --fn-type
58
- document-publish|document-create|document-update|document-delete|media-library-asset-create|media-library-asset-upda
59
- te|media-library-asset-delete|scheduled-function... | --language ts|js | --javascript | --fn-helpers |
60
- --fn-installer skip|npm|pnpm|yarn] [-i | ]
58
+ document-publish|document-create|document-delete|document-update|media-library-asset-create|media-library-asset-dele
59
+ te|media-library-asset-update|scheduled-function|sync-tag-invalidate... | --language ts|js | --javascript |
60
+ --fn-helpers | --fn-installer skip|npm|pnpm|yarn] [-i | ]
61
61
 
62
62
  ARGUMENTS
63
63
  TYPE (function) Type of resource to add (only "function" is supported)
@@ -72,9 +72,9 @@ FLAGS
72
72
  <options: skip|npm|pnpm|yarn>
73
73
  --fn-type=<option>... Document change event(s) that should trigger the function; you can specify multiple
74
74
  events by specifying this flag multiple times
75
- <options:
76
- document-publish|document-create|document-update|document-delete|media-library-asset-cr
77
- eate|media-library-asset-update|media-library-asset-delete|scheduled-function>
75
+ <options: document-publish|document-create|document-delete|document-update|media-librar
76
+ y-asset-create|media-library-asset-delete|media-library-asset-update|scheduled-function
77
+ |sync-tag-invalidate>
78
78
  --javascript Use JavaScript instead of TypeScript
79
79
  --json Format output as json
80
80
  --language=<option> [default: ts] Language of the new function
@@ -101,7 +101,7 @@ EXAMPLES
101
101
  $ sanity-run blueprints add function --name my-function --fn-type document-create --fn-type document-update --lang js
102
102
  ```
103
103
 
104
- _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/add.ts)_
104
+ _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/add.ts)_
105
105
 
106
106
  ## `sanity-run blueprints config`
107
107
 
@@ -109,8 +109,8 @@ View or edit the local Blueprint configuration
109
109
 
110
110
  ```
111
111
  USAGE
112
- $ sanity-run blueprints config [--json] [--validate-resources] [--project-id <value> -e] [--organization-id <value> ]
113
- [--stack <value> ]
112
+ $ sanity-run blueprints config [--json] [--validate-resources] [--stack <value> -e] [--project-id <value> ]
113
+ [--organization-id <value> ]
114
114
 
115
115
  FLAGS
116
116
  -e, --edit Modify the configuration interactively, or directly when combined with ID flags.
@@ -140,7 +140,7 @@ EXAMPLES
140
140
  $ sanity-run blueprints config --edit --project-id <projectId> --stack <name-or-id>
141
141
  ```
142
142
 
143
- _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/config.ts)_
143
+ _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/config.ts)_
144
144
 
145
145
  ## `sanity-run blueprints deploy`
146
146
 
@@ -182,7 +182,7 @@ EXAMPLES
182
182
  $ sanity-run blueprints deploy --fn-installer npm
183
183
  ```
184
184
 
185
- _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/deploy.ts)_
185
+ _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/deploy.ts)_
186
186
 
187
187
  ## `sanity-run blueprints destroy`
188
188
 
@@ -218,7 +218,7 @@ EXAMPLES
218
218
  $ sanity-run blueprints destroy --stack <name-or-id> --project-id <projectId> --force --no-wait
219
219
  ```
220
220
 
221
- _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/destroy.ts)_
221
+ _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/destroy.ts)_
222
222
 
223
223
  ## `sanity-run blueprints doctor`
224
224
 
@@ -250,7 +250,7 @@ EXAMPLES
250
250
  $ sanity-run blueprints doctor --fix
251
251
  ```
252
252
 
253
- _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/doctor.ts)_
253
+ _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/doctor.ts)_
254
254
 
255
255
  ## `sanity-run blueprints info`
256
256
 
@@ -258,11 +258,12 @@ Display the status and resources of the remote Stack deployment
258
258
 
259
259
  ```
260
260
  USAGE
261
- $ sanity-run blueprints info [--json] [--validate-resources] [--stack <value>]
261
+ $ sanity-run blueprints info [--json] [--validate-resources] [--stack <value>] [--project-id <value>]
262
262
 
263
263
  FLAGS
264
264
  --json Format output as json
265
- --stack=<value> Stack name or ID to use instead of the locally configured Stack
265
+ --project-id=<value> Sanity project ID used to scope Blueprint and Stack
266
+ --stack=<value> Stack name or ID
266
267
  --[no-]validate-resources Validate resources
267
268
 
268
269
  DESCRIPTION
@@ -280,9 +281,11 @@ EXAMPLES
280
281
  $ sanity-run blueprints info
281
282
 
282
283
  $ sanity-run blueprints info --stack <name-or-id>
284
+
285
+ $ sanity-run blueprints info --project-id <id> --stack <name-or-id>
283
286
  ```
284
287
 
285
- _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/info.ts)_
288
+ _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/info.ts)_
286
289
 
287
290
  ## `sanity-run blueprints init [DIR]`
288
291
 
@@ -336,7 +339,7 @@ EXAMPLES
336
339
  $ sanity-run blueprints init --blueprint-type <json|js|ts> --stack-name <stackName>
337
340
  ```
338
341
 
339
- _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/init.ts)_
342
+ _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/init.ts)_
340
343
 
341
344
  ## `sanity-run blueprints logs`
342
345
 
@@ -367,7 +370,7 @@ EXAMPLES
367
370
  $ sanity-run blueprints logs --watch
368
371
  ```
369
372
 
370
- _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/logs.ts)_
373
+ _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/logs.ts)_
371
374
 
372
375
  ## `sanity-run blueprints plan`
373
376
 
@@ -395,7 +398,7 @@ EXAMPLES
395
398
  $ sanity-run blueprints plan
396
399
  ```
397
400
 
398
- _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/plan.ts)_
401
+ _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/plan.ts)_
399
402
 
400
403
  ## `sanity-run blueprints stacks`
401
404
 
@@ -427,7 +430,7 @@ EXAMPLES
427
430
  $ sanity-run blueprints stacks --organization-id <organizationId>
428
431
  ```
429
432
 
430
- _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/blueprints/stacks.ts)_
433
+ _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/blueprints/stacks.ts)_
431
434
 
432
435
  ## `sanity-run functions add`
433
436
 
@@ -436,9 +439,9 @@ Add a Function to your Blueprint
436
439
  ```
437
440
  USAGE
438
441
  $ sanity-run functions add [--json] [--validate-resources] [--example <value> | -n <value> | | --language ts|js
439
- | --javascript | | ] [--type document-publish|document-create|document-update|document-delete|media-library-asset-c
440
- reate|media-library-asset-update|media-library-asset-delete|scheduled-function... ] [--helpers] [--installer
441
- skip|npm|pnpm|yarn] [-i | ]
442
+ | --javascript | | ] [--type document-publish|document-create|document-delete|document-update|media-library-asset-c
443
+ reate|media-library-asset-delete|media-library-asset-update|scheduled-function|sync-tag-invalidate... ] [--helpers]
444
+ [--installer skip|npm|pnpm|yarn] [-i | ]
442
445
 
443
446
  FLAGS
444
447
  -i, --install Shortcut for --fn-installer npm
@@ -453,9 +456,9 @@ FLAGS
453
456
  <options: ts|js>
454
457
  --type=<option>... Document change event(s) that should trigger the function; you can specify multiple
455
458
  events by specifying this flag multiple times
456
- <options:
457
- document-publish|document-create|document-update|document-delete|media-library-asset-cr
458
- eate|media-library-asset-update|media-library-asset-delete|scheduled-function>
459
+ <options: document-publish|document-create|document-delete|document-update|media-librar
460
+ y-asset-create|media-library-asset-delete|media-library-asset-update|scheduled-function
461
+ |sync-tag-invalidate>
459
462
  --[no-]validate-resources Validate resources
460
463
 
461
464
  DESCRIPTION
@@ -463,8 +466,8 @@ DESCRIPTION
463
466
 
464
467
  Scaffolds a new Function in the functions/ folder and templates a resource for your Blueprint manifest.
465
468
 
466
- Functions are serverless handlers triggered by document events (create, update, delete, publish) or media library
467
- events.
469
+ Functions are serverless handlers triggered by document, live content or media-library events (create, update, delete,
470
+ publish).
468
471
 
469
472
  After adding, use 'functions dev' to test locally, then 'blueprints deploy' to publish.
470
473
 
@@ -480,7 +483,7 @@ EXAMPLES
480
483
  $ sanity-run functions add --name my-function --type document-create --type document-update --lang js
481
484
  ```
482
485
 
483
- _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/functions/add.ts)_
486
+ _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/functions/add.ts)_
484
487
 
485
488
  ## `sanity-run functions dev`
486
489
 
@@ -516,7 +519,7 @@ EXAMPLES
516
519
  $ sanity-run functions dev --timeout 60
517
520
  ```
518
521
 
519
- _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/functions/dev.ts)_
522
+ _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/functions/dev.ts)_
520
523
 
521
524
  ## `sanity-run functions env add NAME KEY VALUE`
522
525
 
@@ -547,7 +550,7 @@ EXAMPLES
547
550
  $ sanity-run functions env add MyFunction API_URL https://api.example.com/
548
551
  ```
549
552
 
550
- _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/functions/env/add.ts)_
553
+ _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/functions/env/add.ts)_
551
554
 
552
555
  ## `sanity-run functions env list NAME`
553
556
 
@@ -575,7 +578,7 @@ EXAMPLES
575
578
  $ sanity-run functions env list MyFunction
576
579
  ```
577
580
 
578
- _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/functions/env/list.ts)_
581
+ _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/functions/env/list.ts)_
579
582
 
580
583
  ## `sanity-run functions env remove NAME KEY`
581
584
 
@@ -605,7 +608,7 @@ EXAMPLES
605
608
  $ sanity-run functions env remove MyFunction API_URL
606
609
  ```
607
610
 
608
- _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/functions/env/remove.ts)_
611
+ _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/functions/env/remove.ts)_
609
612
 
610
613
  ## `sanity-run functions logs [NAME]`
611
614
 
@@ -647,7 +650,7 @@ EXAMPLES
647
650
  $ sanity-run functions logs <name> --delete
648
651
  ```
649
652
 
650
- _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/functions/logs.ts)_
653
+ _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/functions/logs.ts)_
651
654
 
652
655
  ## `sanity-run functions test [NAME]`
653
656
 
@@ -655,11 +658,11 @@ Invoke a local Sanity Function
655
658
 
656
659
  ```
657
660
  USAGE
658
- $ sanity-run functions test [NAME] [--json] [--validate-resources] [--data-before <value> | [-d <value> | -f
659
- <value> | --document-id <value>] | | | --file-before <value> | --file-after <value> | --document-id-before <value>
660
- | --document-id-after <value>] [--data-after <value> | | | | | | | ] [-e create|update|delete] [-t <value>]
661
- [-a <value>] [--organization-id <value>] [--with-user-token] [--media-library-id <value> | --project-id <value> |
662
- --dataset <value>]
661
+ $ sanity-run functions test [NAME] [--json] [--validate-resources] [--organization-id <value>] [--data-before
662
+ <value> | [-d <value> | -f <value> | --document-id <value>] | | | --file-before <value> | --file-after <value> |
663
+ --document-id-before <value> | --document-id-after <value>] [--data-after <value> | | | | | | | ] [-e
664
+ create|update|delete] [-t <value>] [-a <value>] [--with-user-token] [--media-library-id <value> | --project-id
665
+ <value> | --dataset <value>]
663
666
 
664
667
  ARGUMENTS
665
668
  [NAME] The name of the Sanity Function
@@ -705,7 +708,7 @@ EXAMPLES
705
708
  $ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
706
709
  ```
707
710
 
708
- _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v14.11.0/src/commands/functions/test.ts)_
711
+ _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v14.12.0/src/commands/functions/test.ts)_
709
712
 
710
713
  ## `sanity-run help [COMMAND]`
711
714
 
@@ -3,6 +3,7 @@ import { type Blueprint } from '@sanity/blueprints-parser';
3
3
  import type { Logger } from '../../utils/logger.js';
4
4
  import type { BlueprintParserError, ScopeType } from '../../utils/types.js';
5
5
  import { type LocatedBlueprintsConfig } from './config.js';
6
+ import { type ConfigSource } from './resolve.js';
6
7
  declare const SUPPORTED_FILE_EXTENSIONS: readonly [".json", ".js", ".mjs", ".ts"];
7
8
  type BlueprintFileExtension = (typeof SUPPORTED_FILE_EXTENSIONS)[number];
8
9
  export declare const JSON_BLUEPRINT_CONTENT: {
@@ -23,18 +24,26 @@ type FileInfo = {
23
24
  };
24
25
  /**
25
26
  * Finds the blueprint file in the given path or current working directory
26
- * @param blueprintPath - The path of the blueprint file or directory
27
27
  * @returns The path, file name, and extension of the blueprint file
28
28
  */
29
29
  export declare function findBlueprintFile(blueprintPath?: string): FileInfo | null;
30
+ /** @see resolve.ts for the canonical definition */
31
+ export type { ConfigSource } from './resolve.js';
32
+ /** Result of loading a blueprint file from disk. */
33
+ export interface LoadedBlueprintFile {
34
+ rawBlueprint: Record<string, unknown>;
35
+ module?: BlueprintModule;
36
+ }
30
37
  /**
31
- * Source of the config value.
32
- * - config: from the config file - .sanity.blueprint.config.json most common
33
- * - env: from the environment - usually CLI var like `SANITY_ORGANIZATION_ID`
34
- * - module: from the blueprint module - undocumented escape hatch
35
- * - inferred: legacy `ST-<projectId>` stacks from launch
38
+ * Normalized result from the parser's {@link BlueprintOutput}
39
+ * to match the shape returned by {@link readLocalBlueprint}
36
40
  */
37
- export type ConfigSource = 'config' | 'env' | 'module' | 'inferred';
41
+ export interface ParsedBlueprintContent {
42
+ /** The validated blueprint, or the raw data as fallback when parsing fails */
43
+ parsedBlueprint: Blueprint | Record<string, unknown>;
44
+ errors: BlueprintParserError[];
45
+ resources: BlueprintResource[];
46
+ }
38
47
  /** Result of the blueprint read operation */
39
48
  export interface ReadBlueprintResult {
40
49
  fileInfo: FileInfo;
@@ -46,8 +55,6 @@ export interface ReadBlueprintResult {
46
55
  errors: BlueprintParserError[];
47
56
  /** Validated resources escaped from parser types */
48
57
  resources: BlueprintResource[];
49
- /** @deprecated - use blueprintConfig.configPath instead */
50
- configPath?: string;
51
58
  scopeType?: ScopeType;
52
59
  scopeId?: string;
53
60
  organizationId?: string;
@@ -59,14 +66,24 @@ export interface ReadBlueprintResult {
59
66
  stackId?: ConfigSource;
60
67
  };
61
68
  }
69
+ /**
70
+ * Load a blueprint file from disk: read JSON or import+execute a JS/TS module.
71
+ * Returns the raw blueprint data and the module reference (if dynamic).
72
+ */
73
+ export declare function loadBlueprintFile(fileInfo: FileInfo): Promise<LoadedBlueprintFile>;
74
+ /**
75
+ * Run the blueprint parser/validator on raw blueprint data.
76
+ * Optionally validates function resources.
77
+ */
78
+ export declare function parseBlueprintContent(rawBlueprint: Record<string, unknown>, options: {
79
+ validateResources: boolean;
80
+ }): ParsedBlueprintContent;
62
81
  /**
63
82
  * Reads the blueprint file from disk and parses it.
64
- * Overrides config file values with shell environment variables.
65
- * Can infer stackId from projectId if no stackId is provided and legacy ST-<projectId> stacks from launch are used.
66
- *
67
- * @param logger The logger instance
68
- * @param validate Validation options
69
- * @param blueprintPath - The path of the blueprint file or directory- will search up the directory tree!
83
+ * Resolves IDs from environment > blueprint module > config file.
84
+ * Can infer stackId from projectId for legacy ST-<projectId> stacks.
85
+ * @see {@link loadBlueprintFile} {@link readConfigFile} {@link resolveIds} {@link parseBlueprintContent}
86
+ * @todo deprecate in favor of decomposed functions
70
87
  * @returns Known information about the Blueprint, config, and Stack
71
88
  */
72
89
  export declare function readLocalBlueprint(logger: Logger, validate: {
@@ -80,4 +97,3 @@ export declare function addResourceToBlueprint<T extends BlueprintResource>({ bl
80
97
  blueprintFilePath?: string;
81
98
  resource: T;
82
99
  }): T | undefined;
83
- export {};
@@ -7,7 +7,8 @@ import * as find from 'empathic/find';
7
7
  import { createJiti } from 'jiti';
8
8
  import { SANITY_FUNCTION_DOCUMENT, SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULED, } from '../../constants.js';
9
9
  import { validateResources } from '../../utils/validate/index.js';
10
- import { backfillOrganizationId, backfillProjectBasedStackId, readConfigFile, } from './config.js';
10
+ import { backfillProjectBasedStackId, readConfigFile, } from './config.js';
11
+ import { resolveIds } from './resolve.js';
11
12
  const SUPPORTED_FILE_EXTENSIONS = ['.json', '.js', '.mjs', '.ts'];
12
13
  let SUPPORTED_FILE_NAMES = SUPPORTED_FILE_EXTENSIONS.map((ext) => `blueprint${ext}`);
13
14
  SUPPORTED_FILE_NAMES = [
@@ -29,7 +30,6 @@ export default defineBlueprint({
29
30
  `.trim();
30
31
  /**
31
32
  * Finds the blueprint file in the given path or current working directory
32
- * @param blueprintPath - The path of the blueprint file or directory
33
33
  * @returns The path, file name, and extension of the blueprint file
34
34
  */
35
35
  export function findBlueprintFile(blueprintPath) {
@@ -60,38 +60,29 @@ export function findBlueprintFile(blueprintPath) {
60
60
  };
61
61
  }
62
62
  /**
63
- * Reads the blueprint file from disk and parses it.
64
- * Overrides config file values with shell environment variables.
65
- * Can infer stackId from projectId if no stackId is provided and legacy ST-<projectId> stacks from launch are used.
66
- *
67
- * @param logger The logger instance
68
- * @param validate Validation options
69
- * @param blueprintPath - The path of the blueprint file or directory- will search up the directory tree!
70
- * @returns Known information about the Blueprint, config, and Stack
63
+ * Load a blueprint file from disk: read JSON or import+execute a JS/TS module.
64
+ * Returns the raw blueprint data and the module reference (if dynamic).
71
65
  */
72
- export async function readLocalBlueprint(logger, validate, blueprintPath) {
73
- const blueprintFile = findBlueprintFile(blueprintPath);
74
- if (!blueprintFile)
75
- throw Error('Could not find Blueprint file! Use the `blueprints init` command.');
76
- const { blueprintFilePath: foundFilePath, fileName, extension } = blueprintFile;
66
+ export async function loadBlueprintFile(fileInfo) {
67
+ const { blueprintFilePath, fileName, extension } = fileInfo;
77
68
  let rawBlueprint;
78
69
  let blueprintModule;
79
70
  try {
80
71
  switch (extension) {
81
72
  case '.json': {
82
- const blueprintString = readFileSync(foundFilePath, 'utf8').toString();
73
+ const blueprintString = readFileSync(blueprintFilePath, 'utf8').toString();
83
74
  rawBlueprint = JSON.parse(blueprintString);
84
75
  break;
85
76
  }
86
77
  case '.js':
87
78
  case '.mjs': {
88
- const module = await import(foundFilePath);
89
- blueprintModule = module.default;
79
+ const mod = await import(blueprintFilePath);
80
+ blueprintModule = mod.default;
90
81
  break;
91
82
  }
92
83
  case '.ts': {
93
- const jiti = createJiti(dirname(foundFilePath));
94
- const modDefault = await jiti.import(pathToFileURL(foundFilePath).href, { default: true });
84
+ const jiti = createJiti(dirname(blueprintFilePath));
85
+ const modDefault = await jiti.import(pathToFileURL(blueprintFilePath).href, { default: true });
95
86
  blueprintModule = modDefault;
96
87
  break;
97
88
  }
@@ -102,22 +93,10 @@ export async function readLocalBlueprint(logger, validate, blueprintPath) {
102
93
  catch (err) {
103
94
  throw Error(`Unable to parse Blueprint file: ${fileName}\n${err}`);
104
95
  }
105
- /**
106
- * Org, Project, Stack IDs can be set...
107
- * - in the environment,
108
- * - on the blueprint module,
109
- * - and in the config file.
110
- * The precedence is: environment > blueprint module > config file
111
- */
112
- let moduleOrganizationId;
113
- let moduleProjectId;
114
- let moduleStackId;
96
+ // Dynamic modules: extract attached properties, then execute to get raw blueprint
115
97
  if (blueprintModule) {
116
98
  if (typeof blueprintModule === 'function') {
117
99
  try {
118
- moduleOrganizationId = blueprintModule.organizationId;
119
- moduleProjectId = blueprintModule.projectId;
120
- moduleStackId = blueprintModule.stackId;
121
100
  rawBlueprint = blueprintModule();
122
101
  }
123
102
  catch {
@@ -131,89 +110,14 @@ export async function readLocalBlueprint(logger, validate, blueprintPath) {
131
110
  if (typeof rawBlueprint === 'undefined') {
132
111
  throw Error('Unable to read Blueprint');
133
112
  }
134
- const { SANITY_ORGANIZATION_ID: envOrganizationId, SANITY_PROJECT_ID: envProjectId, SANITY_BLUEPRINT_STACK_ID: envStackId, } = env;
135
- const blueprintConfig = readConfigFile(foundFilePath);
136
- // passively heal config on disk by getting organizationId from projectId
137
- if (blueprintConfig?.projectId && !blueprintConfig.organizationId) {
138
- try {
139
- await backfillOrganizationId({
140
- projectId: blueprintConfig.projectId,
141
- blueprintFilePath: foundFilePath,
142
- logger,
143
- });
144
- }
145
- catch { }
146
- }
147
- const sources = {};
148
- let organizationId;
149
- if (envOrganizationId) {
150
- organizationId = envOrganizationId;
151
- sources.organizationId = 'env';
152
- }
153
- else if (moduleOrganizationId) {
154
- organizationId = moduleOrganizationId;
155
- sources.organizationId = 'module';
156
- }
157
- else if (blueprintConfig?.organizationId) {
158
- organizationId = blueprintConfig.organizationId;
159
- sources.organizationId = 'config';
160
- }
161
- let projectId;
162
- if (envProjectId) {
163
- projectId = envProjectId;
164
- sources.projectId = 'env';
165
- }
166
- else if (moduleProjectId) {
167
- projectId = moduleProjectId;
168
- sources.projectId = 'module';
169
- }
170
- else if (blueprintConfig?.projectId) {
171
- projectId = blueprintConfig.projectId;
172
- sources.projectId = 'config';
173
- }
174
- let stackId;
175
- if (envStackId) {
176
- stackId = envStackId;
177
- sources.stackId = 'env';
178
- }
179
- else if (moduleStackId) {
180
- stackId = moduleStackId;
181
- sources.stackId = 'module';
182
- }
183
- else if (blueprintConfig?.stackId) {
184
- stackId = blueprintConfig.stackId;
185
- sources.stackId = 'config';
186
- }
187
- // LAUNCH LIMIT: 1 Stack per Project - infer stackId from projectId
188
- // this code path exists to handle project-based stacks from initial Blueprints/Functions launch
189
- if (!stackId && projectId) {
190
- try {
191
- // try to assume project-based stack if no stackId is provided
192
- stackId = await backfillProjectBasedStackId({
193
- blueprintFilePath: foundFilePath,
194
- projectId,
195
- logger,
196
- });
197
- if (stackId)
198
- sources.stackId = 'inferred';
199
- }
200
- catch {
201
- // our assumption was wrong, so we'll leave stackId undefined
202
- }
203
- }
204
- let scopeType;
205
- let scopeId;
206
- // Scope is as specific as possible; project > organization
207
- if (projectId) {
208
- scopeType = 'project';
209
- scopeId = projectId;
210
- }
211
- else if (organizationId) {
212
- scopeType = 'organization';
213
- scopeId = organizationId;
214
- }
113
+ return { rawBlueprint, module: blueprintModule };
114
+ }
115
+ /**
116
+ * Run the blueprint parser/validator on raw blueprint data.
117
+ * Optionally validates function resources.
118
+ */
119
+ export function parseBlueprintContent(rawBlueprint, options) {
215
120
  const parserResult = blueprintParserValidator(rawBlueprint, {
216
- // Prevents the following resources from being referenced.
217
121
  invalidReferenceTypes: [
218
122
  SANITY_FUNCTION_DOCUMENT,
219
123
  SANITY_FUNCTION_MEDIA_LIBRARY_ASSET,
@@ -222,34 +126,84 @@ export async function readLocalBlueprint(logger, validate, blueprintPath) {
222
126
  });
223
127
  const parsedBlueprint = parserResult.result === 'valid' ? parserResult.blueprint : undefined;
224
128
  const errors = parserResult.result !== 'valid' ? parserResult.errors : [];
225
- // resource validation
226
- if (parsedBlueprint?.resources) {
227
- if (validate?.resources) {
228
- // validate function resources
229
- errors.push(...validateResources(parsedBlueprint.resources));
230
- }
129
+ if (parsedBlueprint?.resources && options.validateResources) {
130
+ errors.push(...validateResources(parsedBlueprint.resources));
231
131
  }
232
- // Ceremony to cross from parser's Resource type to BlueprintResource
233
- // widen from the parser's Resource type assignable to BlueprintResource
132
+ // Widen from the parser's Resource type to BlueprintResource
234
133
  const parserResources = parsedBlueprint?.resources ?? [];
235
- // filter to valid resources typed as BlueprintResource
236
- const validResources = parserResources.filter((r) => !!r.type);
134
+ const resources = parserResources.filter((r) => !!r.type);
237
135
  return {
238
- fileInfo: { blueprintFilePath: foundFilePath, fileName, extension },
136
+ parsedBlueprint: parsedBlueprint || rawBlueprint,
137
+ errors,
138
+ resources,
139
+ };
140
+ }
141
+ /**
142
+ * Reads the blueprint file from disk and parses it.
143
+ * Resolves IDs from environment > blueprint module > config file.
144
+ * Can infer stackId from projectId for legacy ST-<projectId> stacks.
145
+ * @see {@link loadBlueprintFile} {@link readConfigFile} {@link resolveIds} {@link parseBlueprintContent}
146
+ * @todo deprecate in favor of decomposed functions
147
+ * @returns Known information about the Blueprint, config, and Stack
148
+ */
149
+ export async function readLocalBlueprint(logger, validate, blueprintPath) {
150
+ const fileInfo = findBlueprintFile(blueprintPath);
151
+ if (!fileInfo)
152
+ throw Error('Could not find Blueprint file! Use the `blueprints init` command.');
153
+ // 1. Load blueprint from disk
154
+ const loaded = await loadBlueprintFile(fileInfo);
155
+ const { rawBlueprint } = loaded;
156
+ // 2. Read the config file
157
+ const blueprintConfig = readConfigFile(fileInfo.blueprintFilePath);
158
+ // 3. Resolve IDs: env > module > config
159
+ const resolved = resolveIds({
160
+ env: {
161
+ organizationId: env.SANITY_ORGANIZATION_ID,
162
+ projectId: env.SANITY_PROJECT_ID,
163
+ stackId: env.SANITY_BLUEPRINT_STACK_ID,
164
+ },
165
+ module: loaded.module
166
+ ? {
167
+ organizationId: loaded.module.organizationId,
168
+ projectId: loaded.module.projectId,
169
+ stackId: loaded.module.stackId,
170
+ }
171
+ : undefined,
172
+ config: blueprintConfig
173
+ ? {
174
+ organizationId: blueprintConfig.organizationId,
175
+ projectId: blueprintConfig.projectId,
176
+ stackId: blueprintConfig.stackId,
177
+ }
178
+ : undefined,
179
+ });
180
+ // 4. Legacy stack ID inference: ST-<projectId>
181
+ let { stackId } = resolved;
182
+ if (!stackId && resolved.projectId) {
183
+ try {
184
+ stackId = await backfillProjectBasedStackId({
185
+ blueprintFilePath: fileInfo.blueprintFilePath,
186
+ projectId: resolved.projectId,
187
+ logger,
188
+ });
189
+ if (stackId)
190
+ resolved.sources.stackId = 'inferred';
191
+ }
192
+ catch {
193
+ // assumption was wrong; leave stackId undefined
194
+ }
195
+ }
196
+ // 5. Parse + validate blueprint content
197
+ const parsed = parseBlueprintContent(rawBlueprint, {
198
+ validateResources: validate.resources,
199
+ });
200
+ return {
201
+ fileInfo,
239
202
  blueprintConfig,
240
203
  rawBlueprint,
241
- resources: validResources,
242
- errors,
243
- scopeType,
244
- scopeId,
245
- organizationId,
246
- projectId,
247
- stackId,
248
- sources,
249
- /** @deprecated */
250
- configPath: blueprintConfig?.configPath,
251
- // fallback to the raw blueprint if the parser found errors
252
- parsedBlueprint: parsedBlueprint || rawBlueprint,
204
+ ...parsed,
205
+ ...resolved,
206
+ stackId: stackId ?? resolved.stackId,
253
207
  };
254
208
  }
255
209
  export function writeBlueprintToDisk({ blueprintFilePath, jsonContent = JSON_BLUEPRINT_CONTENT, }) {