@sanity/runtime-cli 17.4.0 → 17.5.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 (43) hide show
  1. package/README.md +50 -47
  2. package/SKILL.md +59 -0
  3. package/dist/actions/blueprints/pre-deploy.d.ts +15 -6
  4. package/dist/actions/blueprints/pre-deploy.js +29 -70
  5. package/dist/actions/blueprints/process-assets.d.ts +29 -0
  6. package/dist/actions/blueprints/process-assets.js +80 -0
  7. package/dist/commands/blueprints/deploy.js +3 -1
  8. package/dist/commands/blueprints/destroy.js +1 -1
  9. package/dist/commands/blueprints/info.d.ts +1 -0
  10. package/dist/commands/blueprints/info.js +5 -0
  11. package/dist/commands/blueprints/init.js +1 -2
  12. package/dist/commands/blueprints/logs.js +1 -0
  13. package/dist/commands/functions/add.js +3 -3
  14. package/dist/commands/functions/dev.js +2 -2
  15. package/dist/commands/functions/logs.d.ts +1 -1
  16. package/dist/commands/functions/logs.js +3 -0
  17. package/dist/cores/blueprints/deploy.js +69 -19
  18. package/dist/cores/functions/add.js +1 -1
  19. package/dist/utils/display/blueprints-formatting.js +3 -3
  20. package/dist/utils/style-text.js +1 -0
  21. package/oclif.manifest.json +20 -15
  22. package/package.json +29 -15
  23. package/skills/_functions-build.md +23 -0
  24. package/skills/_functions-list.md +28 -0
  25. package/skills/blueprints-add.md +8 -0
  26. package/skills/blueprints-config.md +33 -0
  27. package/skills/blueprints-deploy.md +36 -0
  28. package/skills/blueprints-destroy.md +30 -0
  29. package/skills/blueprints-doctor.md +31 -0
  30. package/skills/blueprints-info.md +23 -0
  31. package/skills/blueprints-init.md +48 -0
  32. package/skills/blueprints-logs.md +33 -0
  33. package/skills/blueprints-mint-deploy-token.md +25 -0
  34. package/skills/blueprints-plan.md +28 -0
  35. package/skills/blueprints-promote.md +31 -0
  36. package/skills/blueprints-stacks.md +28 -0
  37. package/skills/functions-add.md +35 -0
  38. package/skills/functions-dev.md +21 -0
  39. package/skills/functions-env-add.md +29 -0
  40. package/skills/functions-env-list.md +21 -0
  41. package/skills/functions-env-remove.md +22 -0
  42. package/skills/functions-logs.md +39 -0
  43. package/skills/functions-test.md +31 -0
package/README.md CHANGED
@@ -90,7 +90,7 @@ EXAMPLES
90
90
  $ sanity-run blueprints add function --name my-function --fn-type document-create --fn-type document-update --lang js
91
91
  ```
92
92
 
93
- _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/add.ts)_
93
+ _See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/add.ts)_
94
94
 
95
95
  ## `sanity-run blueprints config`
96
96
 
@@ -127,7 +127,7 @@ EXAMPLES
127
127
  $ sanity-run blueprints config --edit --project-id <projectId> --stack <name-or-id>
128
128
  ```
129
129
 
130
- _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/config.ts)_
130
+ _See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/config.ts)_
131
131
 
132
132
  ## `sanity-run blueprints deploy`
133
133
 
@@ -160,7 +160,9 @@ DESCRIPTION
160
160
 
161
161
  Use --fn-installer to force which package manager to use when deploying functions.
162
162
 
163
- Set SANITY_ASSET_TIMEOUT (seconds) to override the 60-second timeout for processing resource assets.
163
+ Set SANITY_ASSET_TIMEOUT (seconds) to override the 180-second timeout for processing resource assets.
164
+
165
+ Set SANITY_ASSET_CONCURRENCY to override how many resource assets are processed at once (default 4).
164
166
 
165
167
  Exit codes: 0 deployed, 2 deployment failed, 75 deployment accepted but completion could not be confirmed (rerun
166
168
  'blueprints info' to check).
@@ -181,7 +183,7 @@ EXAMPLES
181
183
  $ sanity-run blueprints deploy --new-stack-name <new-name>
182
184
  ```
183
185
 
184
- _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/deploy.ts)_
186
+ _See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/deploy.ts)_
185
187
 
186
188
  ## `sanity-run blueprints destroy`
187
189
 
@@ -189,16 +191,16 @@ Destroy a remote Stack deployment and its resources
189
191
 
190
192
  ```
191
193
  USAGE
192
- $ sanity-run blueprints destroy [--json] [--project-id <value> --stack <value> --force] [--organization-id <value> ]
194
+ $ sanity-run blueprints destroy [--json] [--project-id <value> --stack <value> -f] [--organization-id <value> ]
193
195
  [--no-wait]
194
196
 
195
197
  FLAGS
196
- --force Force Stack destruction (skip confirmation)
197
- --json Format output as json
198
- --no-wait Do not wait for Stack destruction to complete
199
- --organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
200
- --project-id=<value> Sanity project ID used to scope Blueprint and Stack
201
- --stack=<value> Stack name or ID to destroy (defaults to the locally configured Stack)
198
+ -f, --force Force Stack destruction (skip confirmation)
199
+ --json Format output as json
200
+ --no-wait Do not wait for Stack destruction to complete
201
+ --organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
202
+ --project-id=<value> Sanity project ID used to scope Blueprint and Stack
203
+ --stack=<value> Stack name or ID to destroy (defaults to the locally configured Stack)
202
204
 
203
205
  DESCRIPTION
204
206
  Destroy a remote Stack deployment and its resources
@@ -219,7 +221,7 @@ EXAMPLES
219
221
  $ sanity-run blueprints destroy --stack <name-or-id> --project-id <projectId> --force --no-wait
220
222
  ```
221
223
 
222
- _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/destroy.ts)_
224
+ _See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/destroy.ts)_
223
225
 
224
226
  ## `sanity-run blueprints doctor`
225
227
 
@@ -251,7 +253,7 @@ EXAMPLES
251
253
  $ sanity-run blueprints doctor --fix
252
254
  ```
253
255
 
254
- _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/doctor.ts)_
256
+ _See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/doctor.ts)_
255
257
 
256
258
  ## `sanity-run blueprints info`
257
259
 
@@ -259,13 +261,14 @@ Display the status and resources of the remote Stack deployment
259
261
 
260
262
  ```
261
263
  USAGE
262
- $ sanity-run blueprints info [--json] [--stack <value>] [--project-id <value> | --organization-id <value>]
264
+ $ sanity-run blueprints info [--json] [-v] [--stack <value>] [--project-id <value> | --organization-id <value>]
263
265
 
264
266
  FLAGS
265
- --json Format output as json
266
- --organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
267
- --project-id=<value> Sanity project ID used to scope Blueprint and Stack
268
- --stack=<value> Stack name or ID
267
+ -v, --verbose Show resource and external IDs
268
+ --json Format output as json
269
+ --organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
270
+ --project-id=<value> Sanity project ID used to scope Blueprint and Stack
271
+ --stack=<value> Stack name or ID
269
272
 
270
273
  DESCRIPTION
271
274
  Display the status and resources of the remote Stack deployment
@@ -288,7 +291,7 @@ EXAMPLES
288
291
  $ sanity-run blueprints info --organization-id <orgId> --stack <name-or-id>
289
292
  ```
290
293
 
291
- _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/info.ts)_
294
+ _See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/info.ts)_
292
295
 
293
296
  ## `sanity-run blueprints init [DIR]`
294
297
 
@@ -318,12 +321,12 @@ DESCRIPTION
318
321
 
319
322
  A Blueprint is your local infrastructure-as-code configuration that defines Sanity resources (datasets, functions,
320
323
  etc.). A Stack is the remote deployment target where your Blueprint is applied.
321
- [NOTE: Currently, accounts are limited to three (3) Stacks per project scope.]
322
324
 
323
325
  This is typically the first command you run in a new project. It creates a local Blueprint manifest file
324
326
  (sanity.blueprint.ts, .js, or .json) and provisions a new remote Stack.
325
- Additionally, a Blueprint configuration file is created in .sanity/ containing the scope and Stack IDs. This is
326
- .gitignored by default.
327
+ Additionally, a Blueprint configuration file is created in .sanity/ containing the scope and Stack IDs. A .gitignore
328
+ covering node_modules, .env, and Function build output is created or updated; the .sanity/ config itself is not
329
+ ignored.
327
330
 
328
331
  After initialization, use 'blueprints plan' to preview changes, then 'blueprints deploy' to apply them.
329
332
 
@@ -352,7 +355,7 @@ EXAMPLES
352
355
  $ sanity-run blueprints init old-stack --type <json|js|ts> --project-id <projectId> --stack-id <existingStackId>
353
356
  ```
354
357
 
355
- _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/init.ts)_
358
+ _See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/init.ts)_
356
359
 
357
360
  ## `sanity-run blueprints logs`
358
361
 
@@ -360,8 +363,8 @@ Display logs for the current Blueprint's Stack deployment
360
363
 
361
364
  ```
362
365
  USAGE
363
- $ sanity-run blueprints logs [--json] [--stack <value>] [--project-id <value> | --organization-id <value>] [-l
364
- <value> | -w] [--since <value> | ] [--before <value> | ]
366
+ $ sanity-run blueprints logs [--stack <value>] [--project-id <value> | --organization-id <value>] [-l <value> | [-w
367
+ | --json]] [--since <value> | ] [--before <value> | ]
365
368
 
366
369
  FLAGS
367
370
  -l, --limit=<value> Maximum number of log entries to retrieve (1-500)
@@ -398,7 +401,7 @@ EXAMPLES
398
401
  $ sanity-run blueprints logs --before 2026-05-01T00:00:00Z
399
402
  ```
400
403
 
401
- _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/logs.ts)_
404
+ _See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/logs.ts)_
402
405
 
403
406
  ## `sanity-run blueprints mint-deploy-token`
404
407
 
@@ -443,7 +446,7 @@ EXAMPLES
443
446
  $ sanity-run blueprints mint-deploy-token --organization-id <orgId>
444
447
  ```
445
448
 
446
- _See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/mint-deploy-token.ts)_
449
+ _See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/mint-deploy-token.ts)_
447
450
 
448
451
  ## `sanity-run blueprints plan`
449
452
 
@@ -476,7 +479,7 @@ EXAMPLES
476
479
  $ sanity-run blueprints plan --organization-id <orgId> --stack <name-or-id>
477
480
  ```
478
481
 
479
- _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/plan.ts)_
482
+ _See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/plan.ts)_
480
483
 
481
484
  ## `sanity-run blueprints promote`
482
485
 
@@ -512,7 +515,7 @@ EXAMPLES
512
515
  $ sanity-run blueprints promote --new-stack-name <new-name>
513
516
  ```
514
517
 
515
- _See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/promote.ts)_
518
+ _See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/promote.ts)_
516
519
 
517
520
  ## `sanity-run blueprints stacks`
518
521
 
@@ -548,7 +551,7 @@ EXAMPLES
548
551
  $ sanity-run blueprints stacks --organization-id <organizationId> --include-projects
549
552
  ```
550
553
 
551
- _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/blueprints/stacks.ts)_
554
+ _See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/blueprints/stacks.ts)_
552
555
 
553
556
  ## `sanity-run functions add`
554
557
 
@@ -556,13 +559,13 @@ Add a Function to your Blueprint
556
559
 
557
560
  ```
558
561
  USAGE
559
- $ sanity-run functions add [--json] [--example <value> | -n <value> | | --language ts|js | --javascript | | ]
560
- [--type document-publish|document-create|document-delete|document-update|media-library-asset-create|media-library-as
561
- set-delete|media-library-asset-update|scheduled-function|sync-tag-invalidate... ] [--helpers] [--installer
562
- skip|npm|pnpm|yarn] [-i | ]
562
+ $ sanity-run functions add [--json] [--example <value> | -n <value> | --type
563
+ document-publish|document-create|document-delete|document-update|media-library-asset-create|media-library-asset-dele
564
+ te|media-library-asset-update|scheduled-function|sync-tag-invalidate... | --language ts|js | --javascript |
565
+ --helpers | --installer skip|npm|pnpm|yarn | -i]
563
566
 
564
567
  FLAGS
565
- -i, --install Shortcut for --fn-installer npm
568
+ -i, --install Shortcut for --installer npm
566
569
  -n, --name=<value> Name of the Function to add
567
570
  --example=<value> Example to use for the Function
568
571
  --[no-]helpers Add helpers to the new Function
@@ -600,7 +603,7 @@ EXAMPLES
600
603
  $ sanity-run functions add --name my-function --type document-create --type document-update --lang js
601
604
  ```
602
605
 
603
- _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/functions/add.ts)_
606
+ _See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/functions/add.ts)_
604
607
 
605
608
  ## `sanity-run functions dev`
606
609
 
@@ -624,18 +627,18 @@ DESCRIPTION
624
627
 
625
628
  Open the emulator in your browser to interactively test your functions with the payload editor.
626
629
 
627
- Optionally, set the host and port with the --host and --port flags. Function timeout can be configured with the
628
- --timeout flag.
630
+ Optionally, set the host and port with the --host and --port flags. Port 8974 is reserved for the emulator's
631
+ live-reload WebSocket server. Function timeout can be configured with the --timeout flag.
629
632
 
630
633
  To invoke a function with the CLI, use 'functions test'.
631
634
 
632
635
  EXAMPLES
633
- $ sanity-run functions dev --host 127.0.0.1 --port 8974
636
+ $ sanity-run functions dev --host 127.0.0.1 --port 3333
634
637
 
635
638
  $ sanity-run functions dev --timeout 60
636
639
  ```
637
640
 
638
- _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/functions/dev.ts)_
641
+ _See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/functions/dev.ts)_
639
642
 
640
643
  ## `sanity-run functions env add NAME KEY VALUE`
641
644
 
@@ -668,7 +671,7 @@ EXAMPLES
668
671
  $ sanity-run functions env add --stack <name-or-id> MyFunction API_URL https://api.example.com/
669
672
  ```
670
673
 
671
- _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/functions/env/add.ts)_
674
+ _See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/functions/env/add.ts)_
672
675
 
673
676
  ## `sanity-run functions env list NAME`
674
677
 
@@ -698,7 +701,7 @@ EXAMPLES
698
701
  $ sanity-run functions env list --stack <name-or-id> MyFunction
699
702
  ```
700
703
 
701
- _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/functions/env/list.ts)_
704
+ _See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/functions/env/list.ts)_
702
705
 
703
706
  ## `sanity-run functions env remove NAME KEY`
704
707
 
@@ -730,7 +733,7 @@ EXAMPLES
730
733
  $ sanity-run functions env remove --stack <name-or-id> MyFunction API_URL
731
734
  ```
732
735
 
733
- _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/functions/env/remove.ts)_
736
+ _See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/functions/env/remove.ts)_
734
737
 
735
738
  ## `sanity-run functions logs [NAME]`
736
739
 
@@ -738,7 +741,7 @@ Retrieve or delete logs for a Sanity Function
738
741
 
739
742
  ```
740
743
  USAGE
741
- $ sanity-run functions logs [NAME] [--stack <value>] [-u] [-f [-d | -l <value> | --json]] [-w]
744
+ $ sanity-run functions logs [NAME] [--stack <value>] [-u] [-f [-d | -l <value> | --json]] [-w | ]
742
745
 
743
746
  ARGUMENTS
744
747
  [NAME] The name of the Sanity Function
@@ -770,7 +773,7 @@ EXAMPLES
770
773
  $ sanity-run functions logs <name> --delete
771
774
  ```
772
775
 
773
- _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/functions/logs.ts)_
776
+ _See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/functions/logs.ts)_
774
777
 
775
778
  ## `sanity-run functions test [NAME]`
776
779
 
@@ -827,7 +830,7 @@ EXAMPLES
827
830
  $ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
828
831
  ```
829
832
 
830
- _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.4.0/src/commands/functions/test.ts)_
833
+ _See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.5.0/src/commands/functions/test.ts)_
831
834
 
832
835
  ## `sanity-run help [COMMAND]`
833
836
 
@@ -847,5 +850,5 @@ DESCRIPTION
847
850
  Display help for sanity-run.
848
851
  ```
849
852
 
850
- _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.55/src/commands/help.ts)_
853
+ _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.56/src/commands/help.ts)_
851
854
  <!-- commandsstop -->
package/SKILL.md ADDED
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: sanity-runtime-cli
3
+ description: Use the Sanity `blueprints` and `functions` commands to manage Sanity Blueprints and develop, test, and operate Sanity Functions. Use when an agent needs to inspect or run `blueprints` & `functions` commands, work with Blueprint manifests and remote Stacks, or work with Sanity Function resources.
4
+ ---
5
+
6
+ # Sanity Runtime CLI
7
+
8
+ Typically, the `@sanity/runtime-cli` (`sanity-run`) CLI is not used directly by end-users. The main `@sanity/cli` (`sanity`) loads and uses this CLI internally.
9
+ All `sanity-run` commands can also be run as `sanity <command>` when `@sanity/cli` is available.
10
+ The preferred way to run Sanity commands is with `npx @sanity/cli <command>`.
11
+
12
+ If Sanity authentication has been configured, `sanity-run` may be preferred in environments like CI/CD pipelines for its smaller install size.
13
+
14
+ ## Read command guidance first
15
+
16
+ Before running an unfamiliar command, print its agent-oriented guidance:
17
+
18
+ ```sh
19
+ sanity-run blueprints deploy --skill
20
+ sanity-run functions test --skill
21
+ sanity-run functions env add --skill
22
+ ```
23
+
24
+ `--skill` prints the matching Markdown file and exits without executing the command. `--llms` and `--skills` are aliases.
25
+
26
+ Use `--help` or [README.md](./README.md) for exhaustive arguments and flags. Use `--skill` for command workflows, automation advice, safety checks, and output-handling guidance.
27
+
28
+ ## Find command skill files
29
+
30
+ Command guidance is stored in [skills/](./skills/). Derive filenames from oclif command IDs by replacing colons with hyphens:
31
+
32
+ - `blueprints:deploy` → `skills/blueprints-deploy.md`
33
+ - `functions:test` → `skills/functions-test.md`
34
+ - `functions:env:add` → `skills/functions-env-add.md`
35
+
36
+ Read the file matching the command before invoking it. Follow its guidance for destructive operations, credentials, environment variables, and long-running commands.
37
+
38
+ ## Resolve the target
39
+
40
+ Most `blueprints` commands and every `functions` command that touches remote state need a scope (project or organization), a Stack, and a token. Each is resolved independently, in this order:
41
+
42
+ 1. Command flags, such as `--project-id`, `--organization-id`, and `--stack`.
43
+ 2. Environment variables: `SANITY_PROJECT_ID`, `SANITY_ORGANIZATION_ID`, `SANITY_BLUEPRINT_STACK_ID`.
44
+ 3. Values exported by the Blueprint manifest.
45
+ 4. `.sanity/blueprint.config.json`.
46
+
47
+ When both a project ID and an organization ID resolve, project scope wins. Prefer explicit flags in CI and when correcting a misconfigured target; a value inherited from a lower-priority source is easy to miss.
48
+
49
+ `SANITY_AUTH_TOKEN` supplies the token, otherwise it is read from the `@sanity/cli` login config. `SANITY_BLUEPRINT_PATH` points at a Blueprint file or its directory when it is not discoverable from the working directory.
50
+
51
+ ## Choose a command family
52
+
53
+ - Use `blueprints` commands to manage local Blueprint manifests and remote Stack deployments.
54
+ - Use `functions` commands to scaffold, build, emulate, test, and operate Sanity Functions.
55
+
56
+ ## Read Sanity documentation
57
+
58
+ - [Sanity Blueprints](https://www.sanity.io/docs/blueprints)
59
+ - [Sanity Functions](https://www.sanity.io/docs/functions)
@@ -1,6 +1,7 @@
1
1
  import type { BlueprintResource } from '@sanity/blueprints';
2
2
  import type { Logger } from '../../utils/logger.js';
3
3
  import { type AuthParams, type InstallerType, type ScopeType } from '../../utils/types.js';
4
+ import { type ProcessAssetsProgress, type ProcessedAsset } from './process-assets.js';
4
5
  type PreDeployResult = {
5
6
  success: false;
6
7
  error: string;
@@ -10,11 +11,14 @@ type PreDeployResult = {
10
11
  } | {
11
12
  success: true;
12
13
  };
13
- type PreDeployResourceOptions = {
14
- auth: AuthParams;
15
- blueprintFileDir: string;
16
- installer: InstallerType;
17
- log: Logger;
14
+ export type PreDeployAssetEvent = {
15
+ type: 'progress';
16
+ progress: ProcessAssetsProgress;
17
+ } | {
18
+ type: 'complete';
19
+ } | {
20
+ type: 'result';
21
+ result: ProcessedAsset;
18
22
  };
19
23
  type PreDeployOptions = {
20
24
  scopeType: ScopeType;
@@ -24,6 +28,11 @@ type PreDeployOptions = {
24
28
  stackName: string;
25
29
  bin: string;
26
30
  verbose: boolean | undefined;
27
- } & PreDeployResourceOptions;
31
+ auth: AuthParams;
32
+ blueprintFileDir: string;
33
+ installer: InstallerType;
34
+ logger: Logger;
35
+ onAssetEvent?: (event: PreDeployAssetEvent) => void;
36
+ };
28
37
  export declare function preDeploy(options: PreDeployOptions): Promise<PreDeployResult>;
29
38
  export {};
@@ -1,18 +1,13 @@
1
1
  import { env } from 'node:process';
2
2
  import { resolveDeployedResources } from '../../utils/blueprints/resolve-deployed-resources.js';
3
- import { niceId } from '../../utils/display/presenters.js';
4
3
  import { CODE_OPERATION_UNCONFIRMED, EXIT_OPERATION_UNCONFIRMED } from '../../utils/exit-codes.js';
5
4
  import { styleText } from '../../utils/style-text.js';
6
5
  import { isAssetResource, } from '../../utils/types.js';
7
- import { stashAsset } from './assets.js';
6
+ import { processAssets } from './process-assets.js';
8
7
  import { updateStack } from './stacks.js';
9
8
  import { waitForOperation } from './wait-for-operation.js';
10
- const DEFAULT_ASSET_TIMEOUT = 180;
11
- const assetTimeoutS = Number(process.env.SANITY_ASSET_TIMEOUT) || DEFAULT_ASSET_TIMEOUT;
12
- const assetTimeoutMs = assetTimeoutS * 1000;
13
- const warnTimeoutMs = assetTimeoutMs / 3;
14
9
  export async function preDeploy(options) {
15
- const { resources, stackId, auth, blueprintFileDir, installer, log } = options;
10
+ const { resources, stackId, auth, blueprintFileDir, installer, logger } = options;
16
11
  const hasAssetResources = resources.some(isAssetResource);
17
12
  if (hasAssetResources) {
18
13
  let assetResources;
@@ -26,34 +21,45 @@ export async function preDeploy(options) {
26
21
  resources,
27
22
  stackId,
28
23
  auth,
29
- logger: log,
24
+ logger,
30
25
  });
31
26
  assetResources = resolvedResources.filter(isAssetResource);
32
27
  }
33
28
  else {
34
29
  assetResources = resources.filter(isAssetResource);
35
30
  }
36
- log('Processing assets...');
37
- for (const resource of assetResources) {
38
- const preDeployResult = await preDeployResource(resource, {
31
+ let processedAssets;
32
+ try {
33
+ processedAssets = await processAssets({
34
+ assetResources,
39
35
  auth,
40
36
  blueprintFileDir,
41
37
  installer,
42
- log,
38
+ logger,
39
+ onProgress: (progress) => options.onAssetEvent?.({ type: 'progress', progress }),
40
+ onResult: (result) => options.onAssetEvent?.({ type: 'result', result }),
43
41
  });
44
- if (!preDeployResult.success)
45
- return preDeployResult;
46
- const idx = resources.findIndex((r) => r.name === resource.name);
42
+ }
43
+ finally {
44
+ options.onAssetEvent?.({ type: 'complete' });
45
+ }
46
+ const failure = processedAssets.find((result) => !result.success);
47
+ if (failure)
48
+ return { success: false, error: failure.error };
49
+ // update resources with processed assets
50
+ for (const asset of processedAssets) {
51
+ const idx = resources.findIndex((r) => r.name === asset.resource.name);
52
+ // ! I think this error message is wrong. we somehow have an extra asset
47
53
  if (idx === -1)
48
54
  throw new Error('Unable to update resource asset');
49
- resources[idx] = preDeployResult.resource;
55
+ resources[idx] = asset.resource;
50
56
  }
51
57
  }
52
58
  return { success: true };
53
59
  }
54
60
  async function preDeployStack(options) {
55
- const { scopeType, scopeId, stackId, stackName, resources, auth, log, bin, verbose } = options;
56
- const spinner = log.ora('Starting pre-deploy...').start();
61
+ const { scopeType, scopeId, stackId, stackName, resources, auth, logger, bin, verbose } = options;
62
+ const spinner = logger.ora('Starting pre-deploy...').start();
57
63
  const stackMutation = {
58
64
  scopeType,
59
65
  scopeId,
@@ -61,7 +67,7 @@ async function preDeployStack(options) {
61
67
  preDeploy: true,
62
68
  document: { resources },
63
69
  };
64
- const { ok: deployOk, stack, error: deployError, } = await updateStack({ stackId, stackMutation, auth, logger: log });
70
+ const { ok: deployOk, stack, error: deployError, } = await updateStack({ stackId, stackMutation, auth, logger });
65
71
  if (!deployOk) {
66
72
  spinner.fail(`${styleText('red', 'Failed')} to complete Stack pre-deployment`);
67
73
  return {
@@ -74,19 +80,19 @@ async function preDeployStack(options) {
74
80
  };
75
81
  }
76
82
  spinner.stop().clear();
77
- log(styleText('dim', 'Stack deployment progress:'));
78
- log('');
83
+ logger(styleText('dim', 'Stack deployment progress:'));
84
+ logger('');
79
85
  const outcome = await waitForOperation({
80
86
  stackId,
81
87
  operationId: stack.operationId,
82
88
  auth,
83
- log,
89
+ log: logger,
84
90
  bin,
85
91
  verbose,
86
92
  progressNoun: 'pre-deployment',
87
93
  });
88
94
  if (outcome.type === 'completed') {
89
- log(styleText(['bold', 'green'], 'Stack pre-deployment completed!'));
95
+ logger(styleText(['bold', 'green'], 'Stack pre-deployment completed!'));
90
96
  }
91
97
  else if (outcome.type === 'unconfirmed') {
92
98
  return {
@@ -115,50 +121,3 @@ async function preDeployStack(options) {
115
121
  }
116
122
  return { success: true };
117
123
  }
118
- async function preDeployResource(resource, options) {
119
- const { auth, blueprintFileDir, installer, log } = options;
120
- const fnSpinner = log.ora({ text: `Processing ${resource.name}...`, prefixText: ' ' }).start();
121
- const warnTimer = setTimeout(() => {
122
- fnSpinner.text = `Still processing ${resource.name}, this can take a moment...`;
123
- }, warnTimeoutMs);
124
- let assetTimeoutTimer;
125
- let result;
126
- try {
127
- result = await Promise.race([
128
- stashAsset({ resource, blueprintFileDir, auth, logger: log, installer }),
129
- new Promise((_, reject) => {
130
- assetTimeoutTimer = setTimeout(() => {
131
- reject(new Error(`Processing ${resource.name} timed out after ${assetTimeoutS}s`));
132
- }, assetTimeoutMs);
133
- }),
134
- ]);
135
- }
136
- catch (err) {
137
- const msg = err instanceof Error ? err.message : String(err);
138
- fnSpinner.fail(msg);
139
- return { success: false, error: msg };
140
- }
141
- finally {
142
- clearTimeout(warnTimer);
143
- clearTimeout(assetTimeoutTimer);
144
- }
145
- if (result.success && result.assetId) {
146
- const updatedResource = { ...resource, src: result.assetId };
147
- fnSpinner.succeed(`${updatedResource.name} ${niceId(result.assetId)}`);
148
- log(` Source: ${updatedResource.src}`);
149
- if (result.hash) {
150
- if (result.hash.length > 24) {
151
- log.verbose(` Hash: ${result.hash.slice(0, 8)}...${result.hash.slice(-12)}`);
152
- }
153
- else {
154
- log.verbose(` Hash: ${result.hash}`);
155
- }
156
- }
157
- if (result.exists)
158
- log.verbose(' Asset unchanged');
159
- return { success: true, resource: updatedResource };
160
- }
161
- const errorMsg = `Failed uploading ${resource.name} asset, deploy has stopped`;
162
- fnSpinner.fail(errorMsg);
163
- return { success: false, error: result.error || 'Failed to process asset' };
164
- }
@@ -0,0 +1,29 @@
1
+ import type { Logger } from '../../utils/logger.js';
2
+ import type { AssetResource, AuthParams, InstallerType } from '../../utils/types.js';
3
+ type ProcessAssetsOptions = {
4
+ assetResources: AssetResource[];
5
+ auth: AuthParams;
6
+ blueprintFileDir: string;
7
+ installer: InstallerType;
8
+ logger: Logger;
9
+ onProgress?: (progress: ProcessAssetsProgress) => void;
10
+ onResult?: (result: ProcessedAsset) => void;
11
+ };
12
+ export type ProcessAssetsProgress = {
13
+ completed: number;
14
+ total: number;
15
+ slow: boolean;
16
+ };
17
+ export type ProcessedAsset = {
18
+ success: false;
19
+ resource: AssetResource;
20
+ error: string;
21
+ failureKind: 'processing' | 'upload';
22
+ } | {
23
+ success: true;
24
+ resource: AssetResource;
25
+ hash?: string;
26
+ exists?: boolean;
27
+ };
28
+ export declare function processAssets(options: ProcessAssetsOptions): Promise<ProcessedAsset[]>;
29
+ export {};
@@ -0,0 +1,80 @@
1
+ import { env } from 'node:process';
2
+ import { stashAsset } from './assets.js';
3
+ const DEFAULT_ASSET_CONCURRENCY = 4;
4
+ const DEFAULT_ASSET_TIMEOUT = 180;
5
+ const assetTimeoutS = Number(env.SANITY_ASSET_TIMEOUT) || DEFAULT_ASSET_TIMEOUT;
6
+ const assetTimeoutMs = assetTimeoutS * 1000;
7
+ const warnTimeoutMs = assetTimeoutMs / 3;
8
+ export async function processAssets(options) {
9
+ const { assetResources, onProgress, onResult } = options;
10
+ const total = assetResources.length;
11
+ const processedAssets = [];
12
+ const concurrency = getAssetConcurrency();
13
+ let completed = 0;
14
+ let slow = false;
15
+ const reportProgress = () => onProgress?.({ completed, total, slow });
16
+ reportProgress();
17
+ const warnTimer = setTimeout(() => {
18
+ slow = true;
19
+ reportProgress();
20
+ }, warnTimeoutMs);
21
+ try {
22
+ for (let start = 0; start < total; start += concurrency) {
23
+ const batch = assetResources.slice(start, start + concurrency);
24
+ const batchResults = await Promise.all(batch.map(async (resource) => {
25
+ const result = await processAsset(resource, options);
26
+ completed += 1;
27
+ reportProgress();
28
+ onResult?.(result);
29
+ return result;
30
+ }));
31
+ processedAssets.push(...batchResults);
32
+ if (batchResults.some((result) => !result.success))
33
+ break;
34
+ }
35
+ }
36
+ finally {
37
+ clearTimeout(warnTimer);
38
+ }
39
+ return processedAssets;
40
+ }
41
+ function getAssetConcurrency() {
42
+ const configured = Number(env.SANITY_ASSET_CONCURRENCY);
43
+ return Number.isSafeInteger(configured) && configured > 0 ? configured : DEFAULT_ASSET_CONCURRENCY;
44
+ }
45
+ async function processAsset(resource, options) {
46
+ const { auth, blueprintFileDir, installer, logger } = options;
47
+ let assetTimeoutTimer;
48
+ let result;
49
+ try {
50
+ result = await Promise.race([
51
+ stashAsset({ resource, blueprintFileDir, auth, logger, installer }),
52
+ new Promise((_, reject) => {
53
+ assetTimeoutTimer = setTimeout(() => {
54
+ reject(new Error(`Processing ${resource.name} timed out after ${assetTimeoutS}s`));
55
+ }, assetTimeoutMs);
56
+ }),
57
+ ]);
58
+ }
59
+ catch (err) {
60
+ const msg = err instanceof Error ? err.message : String(err);
61
+ return { success: false, resource, error: msg, failureKind: 'processing' };
62
+ }
63
+ finally {
64
+ clearTimeout(assetTimeoutTimer);
65
+ }
66
+ if (result.success && result.assetId) {
67
+ return {
68
+ success: true,
69
+ resource: { ...resource, src: result.assetId },
70
+ hash: result.hash,
71
+ exists: result.exists,
72
+ };
73
+ }
74
+ return {
75
+ success: false,
76
+ resource,
77
+ error: result.error || 'Failed to process asset',
78
+ failureKind: 'upload',
79
+ };
80
+ }