@sanity/runtime-cli 17.2.0 → 17.3.0-blueprinit.g6a63623
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 +36 -27
- package/SKILL.md +21 -0
- package/dist/actions/blueprinit/manifest.d.ts +13 -0
- package/dist/actions/blueprinit/manifest.js +57 -0
- package/dist/actions/blueprinit/studio.d.ts +6 -0
- package/dist/actions/blueprinit/studio.js +43 -0
- package/dist/actions/blueprinit/templates.d.ts +34 -0
- package/dist/actions/blueprinit/templates.js +83 -0
- package/dist/actions/blueprinit/workspace.d.ts +15 -0
- package/dist/actions/blueprinit/workspace.js +142 -0
- package/dist/actions/blueprints/assets.js +15 -24
- package/dist/actions/blueprints/pre-deploy.d.ts +29 -0
- package/dist/actions/blueprints/pre-deploy.js +164 -0
- package/dist/actions/sanity/datasets.d.ts +15 -0
- package/dist/actions/sanity/datasets.js +26 -0
- package/dist/commands/blueprinit.d.ts +17 -0
- package/dist/commands/blueprinit.js +59 -0
- package/dist/commands/functions/env/add.d.ts +3 -0
- package/dist/commands/functions/env/add.js +6 -2
- package/dist/commands/functions/env/list.d.ts +3 -0
- package/dist/commands/functions/env/list.js +9 -3
- package/dist/commands/functions/env/remove.d.ts +3 -0
- package/dist/commands/functions/env/remove.js +9 -3
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/cores/blueprinit/adopt.d.ts +6 -0
- package/dist/cores/blueprinit/adopt.js +108 -0
- package/dist/cores/blueprinit/finish.d.ts +14 -0
- package/dist/cores/blueprinit/finish.js +64 -0
- package/dist/cores/blueprinit/fresh.d.ts +3 -0
- package/dist/cores/blueprinit/fresh.js +108 -0
- package/dist/cores/blueprinit/preview.d.ts +14 -0
- package/dist/cores/blueprinit/preview.js +13 -0
- package/dist/cores/blueprinit/prompts.d.ts +4 -0
- package/dist/cores/blueprinit/prompts.js +16 -0
- package/dist/cores/blueprinit/selection.d.ts +15 -0
- package/dist/cores/blueprinit/selection.js +90 -0
- package/dist/cores/blueprinit/types.d.ts +16 -0
- package/dist/cores/blueprinit/types.js +1 -0
- package/dist/cores/blueprinit.d.ts +7 -0
- package/dist/cores/blueprinit.js +48 -0
- package/dist/cores/blueprints/deploy.js +16 -64
- package/dist/server/static/vendor/vendor.bundle.js +10 -14
- package/dist/utils/functions/child-process-wrapper.js +13 -171
- package/dist/utils/functions/child-runtime/console.d.ts +1 -0
- package/dist/utils/functions/child-runtime/console.js +50 -0
- package/dist/utils/functions/child-runtime/invoke.d.ts +4 -0
- package/dist/utils/functions/child-runtime/invoke.js +47 -0
- package/dist/utils/functions/child-runtime/resources.d.ts +4 -0
- package/dist/utils/functions/child-runtime/resources.js +59 -0
- package/dist/utils/studios/prepare-asset.d.ts +6 -0
- package/dist/utils/studios/prepare-asset.js +139 -0
- package/dist/utils/types.d.ts +4 -7
- package/dist/utils/types.js +2 -3
- package/oclif.manifest.json +135 -7
- package/package.json +26 -16
- package/skills/blueprinit.md +148 -0
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/17.
|
|
23
|
+
@sanity/runtime-cli/17.3.0-blueprinit.g6a63623 linux-x64 node-v24.18.0
|
|
24
24
|
$ sanity-run --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ sanity-run COMMAND
|
|
@@ -103,7 +103,7 @@ EXAMPLES
|
|
|
103
103
|
$ sanity-run blueprints add function --name my-function --fn-type document-create --fn-type document-update --lang js
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
106
|
+
_See code: [src/commands/blueprints/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/add.ts)_
|
|
107
107
|
|
|
108
108
|
## `sanity-run blueprints config`
|
|
109
109
|
|
|
@@ -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/v17.
|
|
143
|
+
_See code: [src/commands/blueprints/config.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/config.ts)_
|
|
144
144
|
|
|
145
145
|
## `sanity-run blueprints deploy`
|
|
146
146
|
|
|
@@ -194,7 +194,7 @@ EXAMPLES
|
|
|
194
194
|
$ sanity-run blueprints deploy --new-stack-name <new-name>
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
197
|
+
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/deploy.ts)_
|
|
198
198
|
|
|
199
199
|
## `sanity-run blueprints destroy`
|
|
200
200
|
|
|
@@ -232,7 +232,7 @@ EXAMPLES
|
|
|
232
232
|
$ sanity-run blueprints destroy --stack <name-or-id> --project-id <projectId> --force --no-wait
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
-
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
235
|
+
_See code: [src/commands/blueprints/destroy.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/destroy.ts)_
|
|
236
236
|
|
|
237
237
|
## `sanity-run blueprints doctor`
|
|
238
238
|
|
|
@@ -264,7 +264,7 @@ EXAMPLES
|
|
|
264
264
|
$ sanity-run blueprints doctor --fix
|
|
265
265
|
```
|
|
266
266
|
|
|
267
|
-
_See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
267
|
+
_See code: [src/commands/blueprints/doctor.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/doctor.ts)_
|
|
268
268
|
|
|
269
269
|
## `sanity-run blueprints info`
|
|
270
270
|
|
|
@@ -301,7 +301,7 @@ EXAMPLES
|
|
|
301
301
|
$ sanity-run blueprints info --organization-id <orgId> --stack <name-or-id>
|
|
302
302
|
```
|
|
303
303
|
|
|
304
|
-
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
304
|
+
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/info.ts)_
|
|
305
305
|
|
|
306
306
|
## `sanity-run blueprints init [DIR]`
|
|
307
307
|
|
|
@@ -365,7 +365,7 @@ EXAMPLES
|
|
|
365
365
|
$ sanity-run blueprints init old-stack --type <json|js|ts> --project-id <projectId> --stack-id <existingStackId>
|
|
366
366
|
```
|
|
367
367
|
|
|
368
|
-
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
368
|
+
_See code: [src/commands/blueprints/init.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/init.ts)_
|
|
369
369
|
|
|
370
370
|
## `sanity-run blueprints logs`
|
|
371
371
|
|
|
@@ -411,7 +411,7 @@ EXAMPLES
|
|
|
411
411
|
$ sanity-run blueprints logs --before 2026-05-01T00:00:00Z
|
|
412
412
|
```
|
|
413
413
|
|
|
414
|
-
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
414
|
+
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/logs.ts)_
|
|
415
415
|
|
|
416
416
|
## `sanity-run blueprints mint-deploy-token`
|
|
417
417
|
|
|
@@ -456,7 +456,7 @@ EXAMPLES
|
|
|
456
456
|
$ sanity-run blueprints mint-deploy-token --organization-id <orgId>
|
|
457
457
|
```
|
|
458
458
|
|
|
459
|
-
_See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
459
|
+
_See code: [src/commands/blueprints/mint-deploy-token.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/mint-deploy-token.ts)_
|
|
460
460
|
|
|
461
461
|
## `sanity-run blueprints plan`
|
|
462
462
|
|
|
@@ -489,7 +489,7 @@ EXAMPLES
|
|
|
489
489
|
$ sanity-run blueprints plan --organization-id <orgId> --stack <name-or-id>
|
|
490
490
|
```
|
|
491
491
|
|
|
492
|
-
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
492
|
+
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/plan.ts)_
|
|
493
493
|
|
|
494
494
|
## `sanity-run blueprints promote`
|
|
495
495
|
|
|
@@ -525,7 +525,7 @@ EXAMPLES
|
|
|
525
525
|
$ sanity-run blueprints promote --new-stack-name <new-name>
|
|
526
526
|
```
|
|
527
527
|
|
|
528
|
-
_See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
528
|
+
_See code: [src/commands/blueprints/promote.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/promote.ts)_
|
|
529
529
|
|
|
530
530
|
## `sanity-run blueprints stacks`
|
|
531
531
|
|
|
@@ -561,7 +561,7 @@ EXAMPLES
|
|
|
561
561
|
$ sanity-run blueprints stacks --organization-id <organizationId> --include-projects
|
|
562
562
|
```
|
|
563
563
|
|
|
564
|
-
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
564
|
+
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/blueprints/stacks.ts)_
|
|
565
565
|
|
|
566
566
|
## `sanity-run functions add`
|
|
567
567
|
|
|
@@ -613,7 +613,7 @@ EXAMPLES
|
|
|
613
613
|
$ sanity-run functions add --name my-function --type document-create --type document-update --lang js
|
|
614
614
|
```
|
|
615
615
|
|
|
616
|
-
_See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
616
|
+
_See code: [src/commands/functions/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/functions/add.ts)_
|
|
617
617
|
|
|
618
618
|
## `sanity-run functions dev`
|
|
619
619
|
|
|
@@ -648,7 +648,7 @@ EXAMPLES
|
|
|
648
648
|
$ sanity-run functions dev --timeout 60
|
|
649
649
|
```
|
|
650
650
|
|
|
651
|
-
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
651
|
+
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/functions/dev.ts)_
|
|
652
652
|
|
|
653
653
|
## `sanity-run functions env add NAME KEY VALUE`
|
|
654
654
|
|
|
@@ -656,7 +656,7 @@ Add or set an environment variable for a deployed function
|
|
|
656
656
|
|
|
657
657
|
```
|
|
658
658
|
USAGE
|
|
659
|
-
$ sanity-run functions env add NAME KEY VALUE [--json]
|
|
659
|
+
$ sanity-run functions env add NAME KEY VALUE [--json] [--stack <value>]
|
|
660
660
|
|
|
661
661
|
ARGUMENTS
|
|
662
662
|
NAME The name of the Sanity Function
|
|
@@ -664,7 +664,8 @@ ARGUMENTS
|
|
|
664
664
|
VALUE The value of the environment variable
|
|
665
665
|
|
|
666
666
|
FLAGS
|
|
667
|
-
--json
|
|
667
|
+
--json Format output as json
|
|
668
|
+
--stack=<value> Stack name or ID to use instead of the locally configured Stack
|
|
668
669
|
|
|
669
670
|
DESCRIPTION
|
|
670
671
|
Add or set an environment variable for a deployed function
|
|
@@ -676,9 +677,11 @@ DESCRIPTION
|
|
|
676
677
|
|
|
677
678
|
EXAMPLES
|
|
678
679
|
$ sanity-run functions env add MyFunction API_URL https://api.example.com/
|
|
680
|
+
|
|
681
|
+
$ sanity-run functions env add --stack <name-or-id> MyFunction API_URL https://api.example.com/
|
|
679
682
|
```
|
|
680
683
|
|
|
681
|
-
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
684
|
+
_See code: [src/commands/functions/env/add.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/functions/env/add.ts)_
|
|
682
685
|
|
|
683
686
|
## `sanity-run functions env list NAME`
|
|
684
687
|
|
|
@@ -686,13 +689,14 @@ List environment variables for a deployed function
|
|
|
686
689
|
|
|
687
690
|
```
|
|
688
691
|
USAGE
|
|
689
|
-
$ sanity-run functions env list NAME [--json]
|
|
692
|
+
$ sanity-run functions env list NAME [--json] [--stack <value>]
|
|
690
693
|
|
|
691
694
|
ARGUMENTS
|
|
692
695
|
NAME The name of the Sanity Function
|
|
693
696
|
|
|
694
697
|
FLAGS
|
|
695
|
-
--json
|
|
698
|
+
--json Format output as json
|
|
699
|
+
--stack=<value> Stack name or ID to use instead of the locally configured Stack
|
|
696
700
|
|
|
697
701
|
DESCRIPTION
|
|
698
702
|
List environment variables for a deployed function
|
|
@@ -703,9 +707,11 @@ DESCRIPTION
|
|
|
703
707
|
|
|
704
708
|
EXAMPLES
|
|
705
709
|
$ sanity-run functions env list MyFunction
|
|
710
|
+
|
|
711
|
+
$ sanity-run functions env list --stack <name-or-id> MyFunction
|
|
706
712
|
```
|
|
707
713
|
|
|
708
|
-
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
714
|
+
_See code: [src/commands/functions/env/list.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/functions/env/list.ts)_
|
|
709
715
|
|
|
710
716
|
## `sanity-run functions env remove NAME KEY`
|
|
711
717
|
|
|
@@ -713,14 +719,15 @@ Remove an environment variable from a deployed function
|
|
|
713
719
|
|
|
714
720
|
```
|
|
715
721
|
USAGE
|
|
716
|
-
$ sanity-run functions env remove NAME KEY [--json]
|
|
722
|
+
$ sanity-run functions env remove NAME KEY [--json] [--stack <value>]
|
|
717
723
|
|
|
718
724
|
ARGUMENTS
|
|
719
725
|
NAME The name of the Sanity Function
|
|
720
726
|
KEY The name of the environment variable
|
|
721
727
|
|
|
722
728
|
FLAGS
|
|
723
|
-
--json
|
|
729
|
+
--json Format output as json
|
|
730
|
+
--stack=<value> Stack name or ID to use instead of the locally configured Stack
|
|
724
731
|
|
|
725
732
|
DESCRIPTION
|
|
726
733
|
Remove an environment variable from a deployed function
|
|
@@ -732,9 +739,11 @@ DESCRIPTION
|
|
|
732
739
|
|
|
733
740
|
EXAMPLES
|
|
734
741
|
$ sanity-run functions env remove MyFunction API_URL
|
|
742
|
+
|
|
743
|
+
$ sanity-run functions env remove --stack <name-or-id> MyFunction API_URL
|
|
735
744
|
```
|
|
736
745
|
|
|
737
|
-
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
746
|
+
_See code: [src/commands/functions/env/remove.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/functions/env/remove.ts)_
|
|
738
747
|
|
|
739
748
|
## `sanity-run functions logs [NAME]`
|
|
740
749
|
|
|
@@ -774,7 +783,7 @@ EXAMPLES
|
|
|
774
783
|
$ sanity-run functions logs <name> --delete
|
|
775
784
|
```
|
|
776
785
|
|
|
777
|
-
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
786
|
+
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/functions/logs.ts)_
|
|
778
787
|
|
|
779
788
|
## `sanity-run functions test [NAME]`
|
|
780
789
|
|
|
@@ -831,7 +840,7 @@ EXAMPLES
|
|
|
831
840
|
$ sanity-run functions test <name> --event update --data-before '{ "title": "before" }' --data-after '{ "title": "after" }'
|
|
832
841
|
```
|
|
833
842
|
|
|
834
|
-
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.
|
|
843
|
+
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v17.3.0-blueprinit.g6a63623/src/commands/functions/test.ts)_
|
|
835
844
|
|
|
836
845
|
## `sanity-run help [COMMAND]`
|
|
837
846
|
|
|
@@ -851,5 +860,5 @@ DESCRIPTION
|
|
|
851
860
|
Display help for sanity-run.
|
|
852
861
|
```
|
|
853
862
|
|
|
854
|
-
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.
|
|
863
|
+
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/6.2.55/src/commands/help.ts)_
|
|
855
864
|
<!-- commandsstop -->
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: runtime-cli
|
|
3
|
+
description: Use the Sanity Runtime CLI for Blueprints and Functions workflows. Use when an agent needs to run or explain sanity-run commands, especially unattended command flows, local Blueprint management, Stack operations, Function development, or the experimental blueprinit command.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sanity Runtime CLI
|
|
7
|
+
|
|
8
|
+
Use `sanity-run <command> --help` for flags and arguments. Use
|
|
9
|
+
`sanity-run <command> --llms` (or `--skill`) for the agent-oriented workflow and examples for that
|
|
10
|
+
command.
|
|
11
|
+
|
|
12
|
+
Read only the command skill relevant to the task:
|
|
13
|
+
|
|
14
|
+
- `blueprinit` → `skills/blueprinit.md`
|
|
15
|
+
- `blueprints deploy` → `skills/blueprints-deploy.md`
|
|
16
|
+
- `functions test` → `skills/functions-test.md`
|
|
17
|
+
|
|
18
|
+
Derive other filenames by joining the command words with hyphens.
|
|
19
|
+
|
|
20
|
+
Command skills are added incrementally. If one is absent, inspect the command's `--help` output and
|
|
21
|
+
the repository implementation before acting.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const STARTER_DOCUMENT_TYPE = "post";
|
|
2
|
+
export declare const STARTER_FUNCTION_NAME = "set-slug";
|
|
3
|
+
export interface BlueprintManifestOptions {
|
|
4
|
+
projectName: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
projectId: string;
|
|
7
|
+
datasetName: string;
|
|
8
|
+
studioName: string;
|
|
9
|
+
studioSrc: string;
|
|
10
|
+
withFunction: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function renderBlueprint(options: BlueprintManifestOptions): string;
|
|
13
|
+
export declare function slugify(value: string): string;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const quote = (value) => `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'")}'`;
|
|
2
|
+
export const STARTER_DOCUMENT_TYPE = 'post';
|
|
3
|
+
export const STARTER_FUNCTION_NAME = 'set-slug';
|
|
4
|
+
export function renderBlueprint(options) {
|
|
5
|
+
const { projectName, displayName, projectId, datasetName, studioName, studioSrc, withFunction } = options;
|
|
6
|
+
const definers = ['defineBlueprint', 'defineDataset', 'defineProject', 'defineStudio'];
|
|
7
|
+
if (withFunction)
|
|
8
|
+
definers.splice(2, 0, 'defineDocumentFunction');
|
|
9
|
+
const functionResource = withFunction
|
|
10
|
+
? ` defineDocumentFunction({
|
|
11
|
+
name: ${quote(STARTER_FUNCTION_NAME)},
|
|
12
|
+
project: ${quote(projectId)},
|
|
13
|
+
event: {
|
|
14
|
+
on: ['create', 'update'],
|
|
15
|
+
filter: "_type == '${STARTER_DOCUMENT_TYPE}' && !defined(slug.current)",
|
|
16
|
+
projection: '{_id, title, slug}',
|
|
17
|
+
},
|
|
18
|
+
}),
|
|
19
|
+
`
|
|
20
|
+
: '';
|
|
21
|
+
// Project references stay literal until the deploy API can resolve resource references here.
|
|
22
|
+
return `import {${definers.join(', ')}} from '@sanity/blueprints'
|
|
23
|
+
|
|
24
|
+
export default defineBlueprint({
|
|
25
|
+
resources: [
|
|
26
|
+
defineProject({
|
|
27
|
+
name: ${quote(projectName)},
|
|
28
|
+
displayName: ${quote(displayName)},
|
|
29
|
+
lifecycle: {
|
|
30
|
+
deletionPolicy: 'retain',
|
|
31
|
+
ownershipAction: {type: 'attach', id: ${quote(projectId)}},
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
defineDataset({
|
|
35
|
+
name: ${quote(datasetName)},
|
|
36
|
+
project: ${quote(projectId)},
|
|
37
|
+
lifecycle: {
|
|
38
|
+
deletionPolicy: 'retain',
|
|
39
|
+
ownershipAction: {type: 'attach', id: ${quote(datasetName)}, projectId: ${quote(projectId)}},
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
defineStudio({
|
|
43
|
+
name: ${quote(studioName)},
|
|
44
|
+
src: ${quote(studioSrc)},
|
|
45
|
+
autoUpdates: {enabled: true},
|
|
46
|
+
project: ${quote(projectId)},
|
|
47
|
+
}),
|
|
48
|
+
${functionResource} ],
|
|
49
|
+
})
|
|
50
|
+
`;
|
|
51
|
+
}
|
|
52
|
+
export function slugify(value) {
|
|
53
|
+
return value
|
|
54
|
+
.toLowerCase()
|
|
55
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
56
|
+
.replace(/^-+|-+$/g, '');
|
|
57
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const STUDIO_CONFIG_PATTERN = /^sanity\.config\.[cm]?[jt]sx?$/;
|
|
4
|
+
const STUDIO_CLI_PATTERN = /^sanity\.cli\.[cm]?[jt]sx?$/;
|
|
5
|
+
export function detectStudio(dir) {
|
|
6
|
+
let entries;
|
|
7
|
+
try {
|
|
8
|
+
entries = readdirSync(dir, { withFileTypes: true })
|
|
9
|
+
.filter((entry) => entry.isFile())
|
|
10
|
+
.map((entry) => entry.name);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const configFile = entries.find((name) => STUDIO_CONFIG_PATTERN.test(name));
|
|
16
|
+
if (!configFile)
|
|
17
|
+
return undefined;
|
|
18
|
+
const detected = { configFile };
|
|
19
|
+
const cliFile = entries.find((name) => STUDIO_CLI_PATTERN.test(name));
|
|
20
|
+
for (const file of [configFile, cliFile]) {
|
|
21
|
+
if (!file)
|
|
22
|
+
continue;
|
|
23
|
+
const source = readSource(join(dir, file));
|
|
24
|
+
if (!source)
|
|
25
|
+
continue;
|
|
26
|
+
detected.projectId ??= extractLiteral(source, 'projectId');
|
|
27
|
+
detected.dataset ??= extractLiteral(source, 'dataset');
|
|
28
|
+
if (detected.projectId && detected.dataset)
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
return detected;
|
|
32
|
+
}
|
|
33
|
+
function readSource(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
return readFileSync(filePath, 'utf8');
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function extractLiteral(source, key) {
|
|
42
|
+
return source.match(new RegExp(`\\b${key}\\s*:\\s*(['"\`])([^'"\`\\\\]+)\\1`))?.[2];
|
|
43
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare function renderStudioConfig(options: {
|
|
2
|
+
displayName: string;
|
|
3
|
+
projectId: string;
|
|
4
|
+
datasetName: string;
|
|
5
|
+
}): string;
|
|
6
|
+
export declare const STUDIO_SCHEMA_TYPES = "import {post} from './post'\n\nexport const schemaTypes = [post]\n";
|
|
7
|
+
export declare const STUDIO_POST_TYPE = "import {defineField, defineType} from 'sanity'\n\nexport const post = defineType({\n name: 'post',\n title: 'Post',\n type: 'document',\n fields: [\n defineField({name: 'title', type: 'string', validation: (rule) => rule.required()}),\n // The set-slug function fills this when it is empty.\n defineField({name: 'slug', type: 'slug', options: {source: 'title'}}),\n defineField({name: 'publishedAt', title: 'Published at', type: 'datetime'}),\n defineField({name: 'body', type: 'text'}),\n ],\n})\n";
|
|
8
|
+
export declare const FUNCTION_SET_SLUG = "import {createClient} from '@sanity/client'\nimport {documentEventHandler} from '@sanity/functions'\n\nconst slugify = (title: string) =>\n title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 96)\n\nexport const handler = documentEventHandler(async ({context, event}) => {\n const {_id, title, slug} = event.data\n if (!title || slug?.current) return\n\n const client = createClient({apiVersion: '2025-05-01', ...context.clientOptions})\n const current = slugify(title)\n await client.patch(_id).set({slug: {_type: 'slug', current}}).commit()\n\n console.log(`Set slug for ${_id}: ${current}`)\n})\n";
|
|
9
|
+
export declare const studioPackageJson: (name: string) => {
|
|
10
|
+
name: string;
|
|
11
|
+
version: string;
|
|
12
|
+
private: boolean;
|
|
13
|
+
scripts: {
|
|
14
|
+
dev: string;
|
|
15
|
+
build: string;
|
|
16
|
+
deploy: string;
|
|
17
|
+
};
|
|
18
|
+
dependencies: {
|
|
19
|
+
react: string;
|
|
20
|
+
'react-dom': string;
|
|
21
|
+
sanity: string;
|
|
22
|
+
'styled-components': string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export declare const functionPackageJson: (name: string) => {
|
|
26
|
+
name: string;
|
|
27
|
+
version: string;
|
|
28
|
+
private: boolean;
|
|
29
|
+
type: string;
|
|
30
|
+
dependencies: {
|
|
31
|
+
'@sanity/client': string;
|
|
32
|
+
'@sanity/functions': string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { STARTER_DOCUMENT_TYPE, STARTER_FUNCTION_NAME } from './manifest.js';
|
|
2
|
+
const quote = (value) => `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'")}'`;
|
|
3
|
+
export function renderStudioConfig(options) {
|
|
4
|
+
return `import {defineConfig} from 'sanity'
|
|
5
|
+
import {structureTool} from 'sanity/structure'
|
|
6
|
+
import {schemaTypes} from './schemaTypes'
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
name: 'default',
|
|
10
|
+
title: ${quote(options.displayName)},
|
|
11
|
+
projectId: ${quote(options.projectId)},
|
|
12
|
+
dataset: ${quote(options.datasetName)},
|
|
13
|
+
plugins: [structureTool()],
|
|
14
|
+
schema: {types: schemaTypes},
|
|
15
|
+
})
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
export const STUDIO_SCHEMA_TYPES = `import {post} from './post'
|
|
19
|
+
|
|
20
|
+
export const schemaTypes = [post]
|
|
21
|
+
`;
|
|
22
|
+
export const STUDIO_POST_TYPE = `import {defineField, defineType} from 'sanity'
|
|
23
|
+
|
|
24
|
+
export const post = defineType({
|
|
25
|
+
name: '${STARTER_DOCUMENT_TYPE}',
|
|
26
|
+
title: 'Post',
|
|
27
|
+
type: 'document',
|
|
28
|
+
fields: [
|
|
29
|
+
defineField({name: 'title', type: 'string', validation: (rule) => rule.required()}),
|
|
30
|
+
// The ${STARTER_FUNCTION_NAME} function fills this when it is empty.
|
|
31
|
+
defineField({name: 'slug', type: 'slug', options: {source: 'title'}}),
|
|
32
|
+
defineField({name: 'publishedAt', title: 'Published at', type: 'datetime'}),
|
|
33
|
+
defineField({name: 'body', type: 'text'}),
|
|
34
|
+
],
|
|
35
|
+
})
|
|
36
|
+
`;
|
|
37
|
+
export const FUNCTION_SET_SLUG = `import {createClient} from '@sanity/client'
|
|
38
|
+
import {documentEventHandler} from '@sanity/functions'
|
|
39
|
+
|
|
40
|
+
const slugify = (title: string) =>
|
|
41
|
+
title
|
|
42
|
+
.toLowerCase()
|
|
43
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
44
|
+
.replace(/^-+|-+$/g, '')
|
|
45
|
+
.slice(0, 96)
|
|
46
|
+
|
|
47
|
+
export const handler = documentEventHandler(async ({context, event}) => {
|
|
48
|
+
const {_id, title, slug} = event.data
|
|
49
|
+
if (!title || slug?.current) return
|
|
50
|
+
|
|
51
|
+
const client = createClient({apiVersion: '2025-05-01', ...context.clientOptions})
|
|
52
|
+
const current = slugify(title)
|
|
53
|
+
await client.patch(_id).set({slug: {_type: 'slug', current}}).commit()
|
|
54
|
+
|
|
55
|
+
console.log(\`Set slug for \${_id}: \${current}\`)
|
|
56
|
+
})
|
|
57
|
+
`;
|
|
58
|
+
export const studioPackageJson = (name) => ({
|
|
59
|
+
name,
|
|
60
|
+
version: '0.1.0',
|
|
61
|
+
private: true,
|
|
62
|
+
scripts: {
|
|
63
|
+
dev: 'sanity dev',
|
|
64
|
+
build: 'sanity build',
|
|
65
|
+
deploy: 'sanity deploy',
|
|
66
|
+
},
|
|
67
|
+
dependencies: {
|
|
68
|
+
react: '^19',
|
|
69
|
+
'react-dom': '^19',
|
|
70
|
+
sanity: '^4',
|
|
71
|
+
'styled-components': '^6',
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
export const functionPackageJson = (name) => ({
|
|
75
|
+
name,
|
|
76
|
+
version: '0.1.0',
|
|
77
|
+
private: true,
|
|
78
|
+
type: 'module',
|
|
79
|
+
dependencies: {
|
|
80
|
+
'@sanity/client': '^7',
|
|
81
|
+
'@sanity/functions': '^1',
|
|
82
|
+
},
|
|
83
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface WorkspaceOptions {
|
|
2
|
+
dir: string;
|
|
3
|
+
projectId: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
datasetName: string;
|
|
6
|
+
stackName: string;
|
|
7
|
+
studioName: string;
|
|
8
|
+
blueprintsVersion: string;
|
|
9
|
+
}
|
|
10
|
+
export interface WorkspaceResult {
|
|
11
|
+
blueprintFilePath: string;
|
|
12
|
+
files: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function scaffoldWorkspace(options: WorkspaceOptions): WorkspaceResult;
|
|
15
|
+
export declare function adoptWorkspace(options: WorkspaceOptions): WorkspaceResult;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, posix } from 'node:path';
|
|
3
|
+
import { renderBlueprint, STARTER_FUNCTION_NAME } from './manifest.js';
|
|
4
|
+
import { FUNCTION_SET_SLUG, functionPackageJson, renderStudioConfig, STUDIO_POST_TYPE, STUDIO_SCHEMA_TYPES, studioPackageJson, } from './templates.js';
|
|
5
|
+
const GITIGNORE_ENTRY = '# Sanity Blueprints\n.sanity/';
|
|
6
|
+
const DEFAULT_GITIGNORE = `node_modules
|
|
7
|
+
.env
|
|
8
|
+
|
|
9
|
+
${GITIGNORE_ENTRY}
|
|
10
|
+
`;
|
|
11
|
+
export function scaffoldWorkspace(options) {
|
|
12
|
+
const { dir, studioName } = options;
|
|
13
|
+
assertTargetsAvailable(dir, [
|
|
14
|
+
posix.join('studios', studioName),
|
|
15
|
+
posix.join('functions', STARTER_FUNCTION_NAME),
|
|
16
|
+
]);
|
|
17
|
+
const packageJson = preparePackageJson(options, ['studios/*', 'functions/*']);
|
|
18
|
+
const files = [];
|
|
19
|
+
const write = createWriter(dir, files);
|
|
20
|
+
const blueprintFilePath = write('sanity.blueprint.ts', renderBlueprint({
|
|
21
|
+
...manifestOptions(options),
|
|
22
|
+
studioSrc: `./studios/${studioName}`,
|
|
23
|
+
withFunction: true,
|
|
24
|
+
}));
|
|
25
|
+
write(posix.join('studios', studioName, 'package.json'), formatJson(studioPackageJson(studioName)));
|
|
26
|
+
write(posix.join('studios', studioName, 'sanity.config.ts'), renderStudioConfig(options));
|
|
27
|
+
write(posix.join('studios', studioName, 'schemaTypes', 'index.ts'), STUDIO_SCHEMA_TYPES);
|
|
28
|
+
write(posix.join('studios', studioName, 'schemaTypes', 'post.ts'), STUDIO_POST_TYPE);
|
|
29
|
+
write(posix.join('studios', studioName, 'static', '.gitkeep'), '');
|
|
30
|
+
write(posix.join('functions', STARTER_FUNCTION_NAME, 'package.json'), formatJson(functionPackageJson(STARTER_FUNCTION_NAME)));
|
|
31
|
+
write(posix.join('functions', STARTER_FUNCTION_NAME, 'index.ts'), FUNCTION_SET_SLUG);
|
|
32
|
+
writePreparedRootFiles(dir, packageJson, files);
|
|
33
|
+
return { blueprintFilePath, files };
|
|
34
|
+
}
|
|
35
|
+
export function adoptWorkspace(options) {
|
|
36
|
+
const { dir } = options;
|
|
37
|
+
const packageJson = preparePackageJson(options, []);
|
|
38
|
+
const files = [];
|
|
39
|
+
const write = createWriter(dir, files);
|
|
40
|
+
const blueprintFilePath = write('sanity.blueprint.ts', renderBlueprint({ ...manifestOptions(options), studioSrc: '.', withFunction: false }));
|
|
41
|
+
writePreparedRootFiles(dir, packageJson, files);
|
|
42
|
+
return { blueprintFilePath, files };
|
|
43
|
+
}
|
|
44
|
+
function manifestOptions(options) {
|
|
45
|
+
return {
|
|
46
|
+
projectName: options.stackName,
|
|
47
|
+
displayName: options.displayName,
|
|
48
|
+
projectId: options.projectId,
|
|
49
|
+
datasetName: options.datasetName,
|
|
50
|
+
studioName: options.studioName,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function assertTargetsAvailable(dir, paths) {
|
|
54
|
+
const conflicts = paths.filter((path) => existsSync(join(dir, path)));
|
|
55
|
+
if (conflicts.length > 0) {
|
|
56
|
+
throw new Error(`Refusing to overwrite existing paths: ${conflicts.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function createWriter(dir, files) {
|
|
60
|
+
return (relativePath, content) => {
|
|
61
|
+
const filePath = join(dir, relativePath);
|
|
62
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
63
|
+
writeFileSync(filePath, content);
|
|
64
|
+
files.push(relativePath);
|
|
65
|
+
return filePath;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function writePreparedRootFiles(dir, packageJson, files) {
|
|
69
|
+
if (writeGitignore(dir))
|
|
70
|
+
files.push('.gitignore');
|
|
71
|
+
writeFileSync(join(dir, 'package.json'), formatJson(packageJson));
|
|
72
|
+
files.push('package.json');
|
|
73
|
+
}
|
|
74
|
+
function writeGitignore(dir) {
|
|
75
|
+
const filePath = join(dir, '.gitignore');
|
|
76
|
+
if (!existsSync(filePath)) {
|
|
77
|
+
writeFileSync(filePath, DEFAULT_GITIGNORE);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
const existing = readFileSync(filePath, 'utf8');
|
|
81
|
+
if (existing.split(/\r?\n/).some((line) => line.trim() === '.sanity/'))
|
|
82
|
+
return false;
|
|
83
|
+
writeFileSync(filePath, `${existing.trimEnd()}\n\n${GITIGNORE_ENTRY}\n`);
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
function preparePackageJson(options, requiredWorkspaces) {
|
|
87
|
+
const filePath = join(options.dir, 'package.json');
|
|
88
|
+
const parsed = existsSync(filePath)
|
|
89
|
+
? JSON.parse(readFileSync(filePath, 'utf8'))
|
|
90
|
+
: {
|
|
91
|
+
name: options.stackName,
|
|
92
|
+
version: '0.1.0',
|
|
93
|
+
private: true,
|
|
94
|
+
type: 'module',
|
|
95
|
+
};
|
|
96
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
97
|
+
throw new Error('The existing package.json must contain a JSON object.');
|
|
98
|
+
}
|
|
99
|
+
const packageJson = parsed;
|
|
100
|
+
addWorkspaces(packageJson, requiredWorkspaces);
|
|
101
|
+
addBlueprintsDependency(packageJson, options.blueprintsVersion);
|
|
102
|
+
return packageJson;
|
|
103
|
+
}
|
|
104
|
+
function addWorkspaces(packageJson, required) {
|
|
105
|
+
if (required.length === 0)
|
|
106
|
+
return;
|
|
107
|
+
if (!packageJson.workspaces) {
|
|
108
|
+
packageJson.workspaces = required;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (Array.isArray(packageJson.workspaces)) {
|
|
112
|
+
packageJson.workspaces = [...new Set([...packageJson.workspaces, ...required])];
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (!packageJson.workspaces || typeof packageJson.workspaces !== 'object') {
|
|
116
|
+
throw new Error('Cannot add generated packages to the existing package.json workspaces.');
|
|
117
|
+
}
|
|
118
|
+
const workspaces = packageJson.workspaces;
|
|
119
|
+
if (Array.isArray(workspaces.packages)) {
|
|
120
|
+
workspaces.packages = [...new Set([...workspaces.packages, ...required])];
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
throw new Error('Cannot add generated packages to the existing package.json workspaces.');
|
|
124
|
+
}
|
|
125
|
+
function addBlueprintsDependency(packageJson, blueprintsVersion) {
|
|
126
|
+
const dependencies = recordOrEmpty(packageJson.dependencies);
|
|
127
|
+
const devDependencies = recordOrEmpty(packageJson.devDependencies);
|
|
128
|
+
if (dependencies['@sanity/blueprints'] || devDependencies['@sanity/blueprints'])
|
|
129
|
+
return;
|
|
130
|
+
packageJson.devDependencies = {
|
|
131
|
+
...devDependencies,
|
|
132
|
+
'@sanity/blueprints': blueprintsVersion,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function recordOrEmpty(value) {
|
|
136
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
137
|
+
? value
|
|
138
|
+
: {};
|
|
139
|
+
}
|
|
140
|
+
function formatJson(value) {
|
|
141
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
142
|
+
}
|