@sanity/cli 7.9.0 → 7.11.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 +163 -22
- package/dist/actions/auth/ensureAuthenticated.js +2 -0
- package/dist/actions/auth/ensureAuthenticated.js.map +1 -1
- package/dist/actions/auth/login/getProvider.js +7 -2
- package/dist/actions/auth/login/getProvider.js.map +1 -1
- package/dist/actions/auth/login/loginInstructions.js +19 -0
- package/dist/actions/auth/login/loginInstructions.js.map +1 -0
- package/dist/actions/dataset/create.js +2 -2
- package/dist/actions/dataset/create.js.map +1 -1
- package/dist/actions/dataset/resolveDataset.js +7 -1
- package/dist/actions/dataset/resolveDataset.js.map +1 -1
- package/dist/actions/deploy/createUserApplication.js +8 -5
- package/dist/actions/deploy/createUserApplication.js.map +1 -1
- package/dist/actions/deploy/deployApp.js +47 -24
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +2 -0
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/graphql/resolveApiGeneration.js +9 -6
- package/dist/actions/graphql/resolveApiGeneration.js.map +1 -1
- package/dist/actions/init/initAction.js +23 -15
- package/dist/actions/init/initAction.js.map +1 -1
- package/dist/actions/manifest/extractCoreAppManifest.js +11 -4
- package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
- package/dist/actions/migration/constants.js +10 -0
- package/dist/actions/migration/constants.js.map +1 -0
- package/dist/actions/migration/ensureApiVersionFormat.js +16 -0
- package/dist/actions/migration/ensureApiVersionFormat.js.map +1 -0
- package/dist/actions/migration/fileExists.js +13 -0
- package/dist/actions/migration/fileExists.js.map +1 -0
- package/dist/actions/migration/prettyMutationFormatter.js +155 -0
- package/dist/actions/migration/prettyMutationFormatter.js.map +1 -0
- package/dist/actions/migration/resolveMigrationScript.js +75 -0
- package/dist/actions/migration/resolveMigrationScript.js.map +1 -0
- package/dist/actions/migration/resolveMigrations.js +50 -0
- package/dist/actions/migration/resolveMigrations.js.map +1 -0
- package/dist/actions/migration/templates/index.js +7 -0
- package/dist/actions/migration/templates/index.js.map +1 -0
- package/dist/actions/migration/templates/minimalAdvanced.js +21 -0
- package/dist/actions/migration/templates/minimalAdvanced.js.map +1 -0
- package/dist/actions/migration/templates/minimalSimple.js +61 -0
- package/dist/actions/migration/templates/minimalSimple.js.map +1 -0
- package/dist/actions/migration/templates/renameField.js +20 -0
- package/dist/actions/migration/templates/renameField.js.map +1 -0
- package/dist/actions/migration/templates/renameType.js +19 -0
- package/dist/actions/migration/templates/renameType.js.map +1 -0
- package/dist/actions/migration/templates/stringToPTE.js +32 -0
- package/dist/actions/migration/templates/stringToPTE.js.map +1 -0
- package/dist/actions/migration/tree.js +111 -0
- package/dist/actions/migration/tree.js.map +1 -0
- package/dist/actions/organizations/getOrganization.js +7 -3
- package/dist/actions/organizations/getOrganization.js.map +1 -1
- package/dist/actions/organizations/validateOrganizationSlug.js +20 -0
- package/dist/actions/organizations/validateOrganizationSlug.js.map +1 -0
- package/dist/actions/preview/previewAction.js +33 -1
- package/dist/actions/preview/previewAction.js.map +1 -1
- package/dist/actions/schema/listSchemas.js +6 -4
- package/dist/actions/schema/listSchemas.js.map +1 -1
- package/dist/actions/tokens/validateRole.js +2 -1
- package/dist/actions/tokens/validateRole.js.map +1 -1
- package/dist/actions/undeploy/runUndeploy.js +13 -4
- package/dist/actions/undeploy/runUndeploy.js.map +1 -1
- package/dist/commands/backups/disable.js +5 -1
- package/dist/commands/backups/disable.js.map +1 -1
- package/dist/commands/backups/download.js +30 -6
- package/dist/commands/backups/download.js.map +1 -1
- package/dist/commands/backups/enable.js +5 -1
- package/dist/commands/backups/enable.js.map +1 -1
- package/dist/commands/backups/list.js +5 -1
- package/dist/commands/backups/list.js.map +1 -1
- package/dist/commands/cors/add.js +15 -7
- package/dist/commands/cors/add.js.map +1 -1
- package/dist/commands/cors/delete.js +6 -1
- package/dist/commands/cors/delete.js.map +1 -1
- package/dist/commands/datasets/alias/create.js +25 -18
- package/dist/commands/datasets/alias/create.js.map +1 -1
- package/dist/commands/datasets/alias/delete.js +15 -8
- package/dist/commands/datasets/alias/delete.js.map +1 -1
- package/dist/commands/datasets/alias/link.js +39 -17
- package/dist/commands/datasets/alias/link.js.map +1 -1
- package/dist/commands/datasets/alias/unlink.js +23 -2
- package/dist/commands/datasets/alias/unlink.js.map +1 -1
- package/dist/commands/datasets/copy.js +18 -2
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/commands/datasets/create.js +8 -2
- package/dist/commands/datasets/create.js.map +1 -1
- package/dist/commands/datasets/delete.js +14 -17
- package/dist/commands/datasets/delete.js.map +1 -1
- package/dist/commands/datasets/embeddings/disable.js +3 -0
- package/dist/commands/datasets/embeddings/disable.js.map +1 -1
- package/dist/commands/datasets/embeddings/enable.js +5 -2
- package/dist/commands/datasets/embeddings/enable.js.map +1 -1
- package/dist/commands/datasets/embeddings/status.js +3 -0
- package/dist/commands/datasets/embeddings/status.js.map +1 -1
- package/dist/commands/datasets/export.js +27 -15
- package/dist/commands/datasets/export.js.map +1 -1
- package/dist/commands/datasets/import.js +3 -3
- package/dist/commands/datasets/import.js.map +1 -1
- package/dist/commands/datasets/visibility/get.js +2 -2
- package/dist/commands/datasets/visibility/get.js.map +1 -1
- package/dist/commands/datasets/visibility/set.js +2 -2
- package/dist/commands/datasets/visibility/set.js.map +1 -1
- package/dist/commands/docs/read.js +3 -3
- package/dist/commands/docs/read.js.map +1 -1
- package/dist/commands/documents/create.js +18 -13
- package/dist/commands/documents/create.js.map +1 -1
- package/dist/commands/documents/delete.js +3 -3
- package/dist/commands/documents/delete.js.map +1 -1
- package/dist/commands/documents/get.js +3 -3
- package/dist/commands/documents/get.js.map +1 -1
- package/dist/commands/documents/query.js +3 -3
- package/dist/commands/documents/query.js.map +1 -1
- package/dist/commands/documents/validate.js +29 -26
- package/dist/commands/documents/validate.js.map +1 -1
- package/dist/commands/graphql/deploy.js +20 -16
- package/dist/commands/graphql/deploy.js.map +1 -1
- package/dist/commands/graphql/undeploy.js +15 -18
- package/dist/commands/graphql/undeploy.js.map +1 -1
- package/dist/commands/hooks/create.js +4 -0
- package/dist/commands/hooks/create.js.map +1 -1
- package/dist/commands/hooks/delete.js +6 -1
- package/dist/commands/hooks/delete.js.map +1 -1
- package/dist/commands/hooks/logs.js +6 -1
- package/dist/commands/hooks/logs.js.map +1 -1
- package/dist/commands/install.js +1 -1
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/login.js +2 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/media/create-aspect.js +20 -8
- package/dist/commands/media/create-aspect.js.map +1 -1
- package/dist/commands/media/delete-aspect.js +31 -16
- package/dist/commands/media/delete-aspect.js.map +1 -1
- package/dist/commands/media/deploy-aspect.js +10 -5
- package/dist/commands/media/deploy-aspect.js.map +1 -1
- package/dist/commands/media/export.js +9 -4
- package/dist/commands/media/export.js.map +1 -1
- package/dist/commands/media/import.js +6 -1
- package/dist/commands/media/import.js.map +1 -1
- package/dist/commands/migrations/create.js +150 -0
- package/dist/commands/migrations/create.js.map +1 -0
- package/dist/commands/migrations/list.js +64 -0
- package/dist/commands/migrations/list.js.map +1 -0
- package/dist/commands/migrations/run.js +306 -0
- package/dist/commands/migrations/run.js.map +1 -0
- package/dist/commands/organizations/create.js +79 -0
- package/dist/commands/organizations/create.js.map +1 -0
- package/dist/commands/organizations/delete.js +100 -0
- package/dist/commands/organizations/delete.js.map +1 -0
- package/dist/commands/organizations/get.js +48 -0
- package/dist/commands/organizations/get.js.map +1 -0
- package/dist/commands/organizations/list.js +60 -0
- package/dist/commands/organizations/list.js.map +1 -0
- package/dist/commands/organizations/update.js +115 -0
- package/dist/commands/organizations/update.js.map +1 -0
- package/dist/commands/preview.js +1 -0
- package/dist/commands/preview.js.map +1 -1
- package/dist/commands/projects/create.js +3 -1
- package/dist/commands/projects/create.js.map +1 -1
- package/dist/commands/schemas/delete.js +23 -2
- package/dist/commands/schemas/delete.js.map +1 -1
- package/dist/commands/schemas/deploy.js +6 -4
- package/dist/commands/schemas/deploy.js.map +1 -1
- package/dist/commands/schemas/extract.js +22 -1
- package/dist/commands/schemas/extract.js.map +1 -1
- package/dist/commands/schemas/list.js +8 -8
- package/dist/commands/schemas/list.js.map +1 -1
- package/dist/commands/tokens/{add.js → create.js} +25 -18
- package/dist/commands/tokens/create.js.map +1 -0
- package/dist/commands/tokens/delete.js +41 -23
- package/dist/commands/tokens/delete.js.map +1 -1
- package/dist/commands/undeploy.js +2 -7
- package/dist/commands/undeploy.js.map +1 -1
- package/dist/commands/users/invite.js +25 -3
- package/dist/commands/users/invite.js.map +1 -1
- package/dist/prompts/promptForOrganizationName.js +2 -1
- package/dist/prompts/promptForOrganizationName.js.map +1 -1
- package/dist/services/organizations.js +45 -2
- package/dist/services/organizations.js.map +1 -1
- package/dist/services/userApplications.js.map +1 -1
- package/dist/topicAliases.js +10 -0
- package/dist/topicAliases.js.map +1 -1
- package/dist/util/formatCliErrorMessages.js +5 -0
- package/dist/util/formatCliErrorMessages.js.map +1 -0
- package/dist/util/organizationAliases.js +12 -0
- package/dist/util/organizationAliases.js.map +1 -0
- package/oclif.config.js +6 -1
- package/oclif.manifest.json +464 -11
- package/package.json +28 -28
- package/dist/commands/tokens/add.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@ Code for sanity cli
|
|
|
6
6
|
|
|
7
7
|
- [@sanity/cli](#sanitycli)
|
|
8
8
|
- [Commands](#commands)
|
|
9
|
+
|
|
9
10
|
<!-- tocstop -->
|
|
10
11
|
|
|
11
12
|
# Commands
|
|
@@ -95,6 +96,11 @@ Code for sanity cli
|
|
|
95
96
|
- [`sanity migrations run [ID]`](#sanity-migrations-run-id)
|
|
96
97
|
- [`sanity openapi get SLUG`](#sanity-openapi-get-slug)
|
|
97
98
|
- [`sanity openapi list`](#sanity-openapi-list)
|
|
99
|
+
- [`sanity organizations create`](#sanity-organizations-create)
|
|
100
|
+
- [`sanity organizations delete ORGANIZATIONID`](#sanity-organizations-delete-organizationid)
|
|
101
|
+
- [`sanity organizations get ORGANIZATIONID`](#sanity-organizations-get-organizationid)
|
|
102
|
+
- [`sanity organizations list`](#sanity-organizations-list)
|
|
103
|
+
- [`sanity organizations update ORGANIZATIONID`](#sanity-organizations-update-organizationid)
|
|
98
104
|
- [`sanity preview [OUTPUTDIR]`](#sanity-preview-outputdir)
|
|
99
105
|
- [`sanity projects create [PROJECTNAME]`](#sanity-projects-create-projectname)
|
|
100
106
|
- [`sanity projects list`](#sanity-projects-list)
|
|
@@ -107,7 +113,7 @@ Code for sanity cli
|
|
|
107
113
|
- [`sanity telemetry disable`](#sanity-telemetry-disable)
|
|
108
114
|
- [`sanity telemetry enable`](#sanity-telemetry-enable)
|
|
109
115
|
- [`sanity telemetry status`](#sanity-telemetry-status)
|
|
110
|
-
- [`sanity tokens
|
|
116
|
+
- [`sanity tokens create [LABEL]`](#sanity-tokens-create-label)
|
|
111
117
|
- [`sanity tokens delete [TOKENID]`](#sanity-tokens-delete-tokenid)
|
|
112
118
|
- [`sanity tokens list`](#sanity-tokens-list)
|
|
113
119
|
- [`sanity typegen generate`](#sanity-typegen-generate)
|
|
@@ -801,13 +807,14 @@ Add a CORS origin to the project
|
|
|
801
807
|
|
|
802
808
|
```
|
|
803
809
|
USAGE
|
|
804
|
-
$ sanity cors add ORIGIN [-p <id>] [--credentials]
|
|
810
|
+
$ sanity cors add ORIGIN [-p <id>] [--credentials] [-y]
|
|
805
811
|
|
|
806
812
|
ARGUMENTS
|
|
807
813
|
ORIGIN Origin to allow (e.g., https://example.com)
|
|
808
814
|
|
|
809
815
|
FLAGS
|
|
810
|
-
|
|
816
|
+
-y, --yes Confirm risky wildcard origins without prompting
|
|
817
|
+
--[no-]credentials Allow credentials (token/cookie) to be sent from this origin
|
|
811
818
|
|
|
812
819
|
OVERRIDE FLAGS
|
|
813
820
|
-p, --project-id=<id> Project ID to add CORS origin to (overrides CLI configuration)
|
|
@@ -1800,8 +1807,9 @@ Validate documents in a dataset against the studio schema
|
|
|
1800
1807
|
|
|
1801
1808
|
```
|
|
1802
1809
|
USAGE
|
|
1803
|
-
$ sanity documents validate [-p <id>] [-d <name>] [--file <value>] [--format
|
|
1804
|
-
[--max-custom-validation-concurrency <value>] [--max-fetch-concurrency <value>] [--workspace
|
|
1810
|
+
$ sanity documents validate [-p <id>] [-d <name>] [--file <value>] [--format json|ndjson|pretty] [--level
|
|
1811
|
+
error|warning|info] [--max-custom-validation-concurrency <value>] [--max-fetch-concurrency <value>] [--workspace
|
|
1812
|
+
<value>] [-y]
|
|
1805
1813
|
|
|
1806
1814
|
FLAGS
|
|
1807
1815
|
-d, --dataset=<name> Override the dataset used. By default, this is derived from the given
|
|
@@ -1809,10 +1817,11 @@ FLAGS
|
|
|
1809
1817
|
-p, --project-id=<id> Override the project ID used. By default, this is derived from the
|
|
1810
1818
|
given workspace
|
|
1811
1819
|
-y, --yes Skips the first confirmation prompt
|
|
1812
|
-
--file=<value>
|
|
1813
|
-
|
|
1814
|
-
--format=<
|
|
1820
|
+
--file=<value> Path to an NDJSON file or tar archive containing an NDJSON file
|
|
1821
|
+
(optionally gzip-compressed)
|
|
1822
|
+
--format=<option> The output format used to print the found validation markers and
|
|
1815
1823
|
report progress
|
|
1824
|
+
<options: json|ndjson|pretty>
|
|
1816
1825
|
--level=<option> [default: warning] The minimum level reported. Defaults to warning
|
|
1817
1826
|
<options: error|warning|info>
|
|
1818
1827
|
--max-custom-validation-concurrency=<value> [default: 5] Specify how many custom validators can run concurrently
|
|
@@ -2523,7 +2532,7 @@ USAGE
|
|
|
2523
2532
|
|
|
2524
2533
|
FLAGS
|
|
2525
2534
|
--[no-]open Open a browser window to log in (`--no-open` only prints URL)
|
|
2526
|
-
--provider=<providerId> Log in using
|
|
2535
|
+
--provider=<providerId> Log in using a provider ID (google, github, sanity, vercel)
|
|
2527
2536
|
--sso=<slug> Log in using Single Sign-On, using the given organization slug
|
|
2528
2537
|
--sso-provider=<name> Select a specific SSO provider by name (use with --sso)
|
|
2529
2538
|
--with-token Read token from standard input
|
|
@@ -2627,7 +2636,11 @@ Create a new aspect definition file
|
|
|
2627
2636
|
|
|
2628
2637
|
```
|
|
2629
2638
|
USAGE
|
|
2630
|
-
$ sanity media create-aspect
|
|
2639
|
+
$ sanity media create-aspect [--name <value>] [--title <value>]
|
|
2640
|
+
|
|
2641
|
+
FLAGS
|
|
2642
|
+
--name=<value> Aspect name. Defaults to the title in camel case
|
|
2643
|
+
--title=<value> Aspect title
|
|
2631
2644
|
|
|
2632
2645
|
DESCRIPTION
|
|
2633
2646
|
Create a new aspect definition file
|
|
@@ -2651,7 +2664,7 @@ ARGUMENTS
|
|
|
2651
2664
|
|
|
2652
2665
|
FLAGS
|
|
2653
2666
|
--media-library-id=<value> The id of the target media library
|
|
2654
|
-
--yes
|
|
2667
|
+
--yes Run without prompts and confirm deletion
|
|
2655
2668
|
|
|
2656
2669
|
OVERRIDE FLAGS
|
|
2657
2670
|
-p, --project-id=<id> Project ID to delete media aspect from (overrides CLI configuration)
|
|
@@ -2919,6 +2932,132 @@ EXAMPLES
|
|
|
2919
2932
|
$ sanity openapi list --web
|
|
2920
2933
|
```
|
|
2921
2934
|
|
|
2935
|
+
## `sanity organizations create`
|
|
2936
|
+
|
|
2937
|
+
Create a new organization
|
|
2938
|
+
|
|
2939
|
+
```
|
|
2940
|
+
USAGE
|
|
2941
|
+
$ sanity organizations create [--default-role <value>] [--name <value>]
|
|
2942
|
+
|
|
2943
|
+
FLAGS
|
|
2944
|
+
--default-role=<value> Default role assigned to new members
|
|
2945
|
+
--name=<value> Organization name
|
|
2946
|
+
|
|
2947
|
+
DESCRIPTION
|
|
2948
|
+
Create a new organization
|
|
2949
|
+
|
|
2950
|
+
EXAMPLES
|
|
2951
|
+
Interactively create an organization
|
|
2952
|
+
|
|
2953
|
+
$ sanity organizations create
|
|
2954
|
+
|
|
2955
|
+
Create an organization named "Acme Corp"
|
|
2956
|
+
|
|
2957
|
+
$ sanity organizations create --name "Acme Corp"
|
|
2958
|
+
|
|
2959
|
+
Create an organization with a default member role
|
|
2960
|
+
|
|
2961
|
+
$ sanity organizations create --name "Acme Corp" --default-role member
|
|
2962
|
+
```
|
|
2963
|
+
|
|
2964
|
+
## `sanity organizations delete ORGANIZATIONID`
|
|
2965
|
+
|
|
2966
|
+
Delete an organization
|
|
2967
|
+
|
|
2968
|
+
```
|
|
2969
|
+
USAGE
|
|
2970
|
+
$ sanity organizations delete ORGANIZATIONID [--force]
|
|
2971
|
+
|
|
2972
|
+
ARGUMENTS
|
|
2973
|
+
ORGANIZATIONID Organization ID to delete
|
|
2974
|
+
|
|
2975
|
+
FLAGS
|
|
2976
|
+
--force Do not prompt for delete confirmation - forcefully delete
|
|
2977
|
+
|
|
2978
|
+
DESCRIPTION
|
|
2979
|
+
Delete an organization
|
|
2980
|
+
|
|
2981
|
+
EXAMPLES
|
|
2982
|
+
Delete an organization (prompts for confirmation)
|
|
2983
|
+
|
|
2984
|
+
$ sanity organizations delete org-abc123
|
|
2985
|
+
|
|
2986
|
+
Delete an organization without confirmation
|
|
2987
|
+
|
|
2988
|
+
$ sanity organizations delete org-abc123 --force
|
|
2989
|
+
```
|
|
2990
|
+
|
|
2991
|
+
## `sanity organizations get ORGANIZATIONID`
|
|
2992
|
+
|
|
2993
|
+
Get details of an organization
|
|
2994
|
+
|
|
2995
|
+
```
|
|
2996
|
+
USAGE
|
|
2997
|
+
$ sanity organizations get ORGANIZATIONID
|
|
2998
|
+
|
|
2999
|
+
ARGUMENTS
|
|
3000
|
+
ORGANIZATIONID Organization ID
|
|
3001
|
+
|
|
3002
|
+
DESCRIPTION
|
|
3003
|
+
Get details of an organization
|
|
3004
|
+
|
|
3005
|
+
EXAMPLES
|
|
3006
|
+
Get details of a specific organization
|
|
3007
|
+
|
|
3008
|
+
$ sanity organizations get org-abc123
|
|
3009
|
+
```
|
|
3010
|
+
|
|
3011
|
+
## `sanity organizations list`
|
|
3012
|
+
|
|
3013
|
+
List organizations you are a member of
|
|
3014
|
+
|
|
3015
|
+
```
|
|
3016
|
+
USAGE
|
|
3017
|
+
$ sanity organizations list
|
|
3018
|
+
|
|
3019
|
+
DESCRIPTION
|
|
3020
|
+
List organizations you are a member of
|
|
3021
|
+
|
|
3022
|
+
EXAMPLES
|
|
3023
|
+
List all your organizations
|
|
3024
|
+
|
|
3025
|
+
$ sanity organizations list
|
|
3026
|
+
```
|
|
3027
|
+
|
|
3028
|
+
## `sanity organizations update ORGANIZATIONID`
|
|
3029
|
+
|
|
3030
|
+
Update an organization
|
|
3031
|
+
|
|
3032
|
+
```
|
|
3033
|
+
USAGE
|
|
3034
|
+
$ sanity organizations update ORGANIZATIONID [--default-role <value>] [--name <value>] [--slug <value>]
|
|
3035
|
+
|
|
3036
|
+
ARGUMENTS
|
|
3037
|
+
ORGANIZATIONID Organization ID
|
|
3038
|
+
|
|
3039
|
+
FLAGS
|
|
3040
|
+
--default-role=<value> New default role for new members
|
|
3041
|
+
--name=<value> New organization name
|
|
3042
|
+
--slug=<value> New URL slug (requires authSAML feature on the organization)
|
|
3043
|
+
|
|
3044
|
+
DESCRIPTION
|
|
3045
|
+
Update an organization
|
|
3046
|
+
|
|
3047
|
+
EXAMPLES
|
|
3048
|
+
Rename an organization
|
|
3049
|
+
|
|
3050
|
+
$ sanity organizations update org-abc123 --name "New Name"
|
|
3051
|
+
|
|
3052
|
+
Set the organization slug (requires authSAML feature)
|
|
3053
|
+
|
|
3054
|
+
$ sanity organizations update org-abc123 --slug new-slug
|
|
3055
|
+
|
|
3056
|
+
Change the default member role
|
|
3057
|
+
|
|
3058
|
+
$ sanity organizations update org-abc123 --default-role viewer
|
|
3059
|
+
```
|
|
3060
|
+
|
|
2922
3061
|
## `sanity preview [OUTPUTDIR]`
|
|
2923
3062
|
|
|
2924
3063
|
Start a local server to preview a production build
|
|
@@ -3024,10 +3163,11 @@ Delete schema documents by id
|
|
|
3024
3163
|
|
|
3025
3164
|
```
|
|
3026
3165
|
USAGE
|
|
3027
|
-
$ sanity schemas delete --ids <value> [-p <id>] [-d <name>] [--verbose]
|
|
3166
|
+
$ sanity schemas delete --ids <value> [-p <id>] [-d <name>] [--verbose] [-y]
|
|
3028
3167
|
|
|
3029
3168
|
FLAGS
|
|
3030
3169
|
-d, --dataset=<name> Delete schemas from a specific dataset
|
|
3170
|
+
-y, --yes Delete schemas without prompting for confirmation
|
|
3031
3171
|
--ids=<value> (required) Comma-separated list of schema ids to delete
|
|
3032
3172
|
--verbose Enable verbose logging
|
|
3033
3173
|
|
|
@@ -3087,11 +3227,12 @@ Extract a JSON representation of a Sanity schema within a Studio context.
|
|
|
3087
3227
|
|
|
3088
3228
|
```
|
|
3089
3229
|
USAGE
|
|
3090
|
-
$ sanity schemas extract [--enforce-required-fields] [--format <format>] [--path <value>] [--watch]
|
|
3230
|
+
$ sanity schemas extract [--enforce-required-fields] [--force] [--format <format>] [--path <value>] [--watch]
|
|
3091
3231
|
[--watch-patterns <glob>...] [--workspace <name>]
|
|
3092
3232
|
|
|
3093
3233
|
FLAGS
|
|
3094
3234
|
--enforce-required-fields Makes the schema generated treat fields marked as required as non-optional
|
|
3235
|
+
--force Overwrite an existing schema file
|
|
3095
3236
|
--format=<format> [default: groq-type-nodes] Output format (currently only groq-type-nodes)
|
|
3096
3237
|
--path=<value> Optional path to specify destination of the schema file
|
|
3097
3238
|
--watch Enable watch mode to re-extract schema on file changes
|
|
@@ -3264,13 +3405,13 @@ EXAMPLES
|
|
|
3264
3405
|
$ sanity telemetry telemetry status
|
|
3265
3406
|
```
|
|
3266
3407
|
|
|
3267
|
-
## `sanity tokens
|
|
3408
|
+
## `sanity tokens create [LABEL]`
|
|
3268
3409
|
|
|
3269
3410
|
Create a new API token for the project
|
|
3270
3411
|
|
|
3271
3412
|
```
|
|
3272
3413
|
USAGE
|
|
3273
|
-
$ sanity tokens
|
|
3414
|
+
$ sanity tokens create [LABEL] [-p <id>] [--json] [--role viewer] [-y]
|
|
3274
3415
|
|
|
3275
3416
|
ARGUMENTS
|
|
3276
3417
|
[LABEL] Label for the new token
|
|
@@ -3278,10 +3419,10 @@ ARGUMENTS
|
|
|
3278
3419
|
FLAGS
|
|
3279
3420
|
-y, --yes Skip prompts and use defaults (unattended mode)
|
|
3280
3421
|
--json Output as JSON
|
|
3281
|
-
--role=viewer Role to assign to the token
|
|
3422
|
+
--role=viewer Role to assign to the token (defaults to viewer in unattended mode)
|
|
3282
3423
|
|
|
3283
3424
|
OVERRIDE FLAGS
|
|
3284
|
-
-p, --project-id=<id> Project ID to
|
|
3425
|
+
-p, --project-id=<id> Project ID to create token in (overrides CLI configuration)
|
|
3285
3426
|
|
|
3286
3427
|
DESCRIPTION
|
|
3287
3428
|
Create a new API token for the project
|
|
@@ -3289,23 +3430,23 @@ DESCRIPTION
|
|
|
3289
3430
|
EXAMPLES
|
|
3290
3431
|
Create a token with a label
|
|
3291
3432
|
|
|
3292
|
-
$ sanity tokens
|
|
3433
|
+
$ sanity tokens create "My API Token"
|
|
3293
3434
|
|
|
3294
3435
|
Create a token with editor role
|
|
3295
3436
|
|
|
3296
|
-
$ sanity tokens
|
|
3437
|
+
$ sanity tokens create "My API Token" --role=editor
|
|
3297
3438
|
|
|
3298
3439
|
Create a token in unattended mode
|
|
3299
3440
|
|
|
3300
|
-
$ sanity tokens
|
|
3441
|
+
$ sanity tokens create "CI Token" --role=editor --yes
|
|
3301
3442
|
|
|
3302
3443
|
Output token information as JSON
|
|
3303
3444
|
|
|
3304
|
-
$ sanity tokens
|
|
3445
|
+
$ sanity tokens create "API Token" --json
|
|
3305
3446
|
|
|
3306
3447
|
Create a token for a specific project
|
|
3307
3448
|
|
|
3308
|
-
$ sanity tokens
|
|
3449
|
+
$ sanity tokens create "My Token" --project-id abc123 --role=editor
|
|
3309
3450
|
```
|
|
3310
3451
|
|
|
3311
3452
|
## `sanity tokens delete [TOKENID]`
|
|
@@ -4,6 +4,7 @@ import { isHttpError } from '@sanity/client';
|
|
|
4
4
|
import { LoginError } from '../../errors/LoginError.js';
|
|
5
5
|
import { getCliUser } from '../../services/user.js';
|
|
6
6
|
import { login } from './login/login.js';
|
|
7
|
+
import { LOGIN_REQUIRED_MESSAGE } from './login/loginInstructions.js';
|
|
7
8
|
/**
|
|
8
9
|
* Ensure the user is authenticated. Validates the current token via /users/me
|
|
9
10
|
* and triggers interactive login if the token is missing or invalid.
|
|
@@ -15,6 +16,7 @@ import { login } from './login/login.js';
|
|
|
15
16
|
*/ export async function ensureAuthenticated(options) {
|
|
16
17
|
const user = await validateSession();
|
|
17
18
|
if (user) return user;
|
|
19
|
+
options.output.warn(LOGIN_REQUIRED_MESSAGE);
|
|
18
20
|
try {
|
|
19
21
|
await login({
|
|
20
22
|
output: options.output,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/auth/ensureAuthenticated.ts"],"sourcesContent":["import {\n type CLITelemetryStore,\n getCliToken,\n type Output,\n type SanityOrgUser,\n} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {LoginError} from '../../errors/LoginError.js'\nimport {getCliUser} from '../../services/user.js'\nimport {login} from './login/login.js'\n\n/**\n * Ensure the user is authenticated. Validates the current token via /users/me\n * and triggers interactive login if the token is missing or invalid.\n *\n * @returns The authenticated user.\n * @throws LoginError if interactive login fails or is cancelled.\n * @throws Error if a network/server error occurs during validation.\n * @internal\n */\nexport async function ensureAuthenticated(options: {\n output: Output\n telemetry: CLITelemetryStore\n}): Promise<SanityOrgUser> {\n const user = await validateSession()\n if (user) return user\n\n try {\n await login({output: options.output, telemetry: options.telemetry})\n } catch (cause) {\n throw new LoginError(getErrorMessage(cause), {cause})\n }\n\n try {\n return await getCliUser()\n } catch (cause) {\n if (isHttpError(cause) && (cause.statusCode === 401 || cause.statusCode === 403)) {\n throw new LoginError(\n `Login succeeded but failed to verify session: ${getErrorMessage(cause)}`,\n {cause},\n )\n }\n throw cause\n }\n}\n\n/**\n * Validate the current CLI auth token by calling /users/me.\n *\n * Returns null only for auth failures (401/403). Re-throws network errors,\n * timeouts, and server errors so callers can handle them appropriately\n * instead of triggering an unnecessary re-login prompt.\n *\n * @returns The authenticated user if valid, null if invalid/missing.\n * @internal\n */\nexport async function validateSession(): Promise<SanityOrgUser | null> {\n const token = await getCliToken()\n if (!token) return null\n\n try {\n return await getCliUser()\n } catch (error) {\n if (isHttpError(error) && (error.statusCode === 401 || error.statusCode === 403)) {\n return null\n }\n throw error\n }\n}\n"],"names":["getCliToken","getErrorMessage","isHttpError","LoginError","getCliUser","login","ensureAuthenticated","options","user","validateSession","output","telemetry","cause","statusCode","token","error"],"mappings":"AAAA,SAEEA,WAAW,QAGN,mBAAkB;AACzB,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,UAAU,QAAO,6BAA4B;AACrD,SAAQC,UAAU,QAAO,yBAAwB;AACjD,SAAQC,KAAK,QAAO,mBAAkB;
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/auth/ensureAuthenticated.ts"],"sourcesContent":["import {\n type CLITelemetryStore,\n getCliToken,\n type Output,\n type SanityOrgUser,\n} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {LoginError} from '../../errors/LoginError.js'\nimport {getCliUser} from '../../services/user.js'\nimport {login} from './login/login.js'\nimport {LOGIN_REQUIRED_MESSAGE} from './login/loginInstructions.js'\n\n/**\n * Ensure the user is authenticated. Validates the current token via /users/me\n * and triggers interactive login if the token is missing or invalid.\n *\n * @returns The authenticated user.\n * @throws LoginError if interactive login fails or is cancelled.\n * @throws Error if a network/server error occurs during validation.\n * @internal\n */\nexport async function ensureAuthenticated(options: {\n output: Output\n telemetry: CLITelemetryStore\n}): Promise<SanityOrgUser> {\n const user = await validateSession()\n if (user) return user\n\n options.output.warn(LOGIN_REQUIRED_MESSAGE)\n\n try {\n await login({output: options.output, telemetry: options.telemetry})\n } catch (cause) {\n throw new LoginError(getErrorMessage(cause), {cause})\n }\n\n try {\n return await getCliUser()\n } catch (cause) {\n if (isHttpError(cause) && (cause.statusCode === 401 || cause.statusCode === 403)) {\n throw new LoginError(\n `Login succeeded but failed to verify session: ${getErrorMessage(cause)}`,\n {cause},\n )\n }\n throw cause\n }\n}\n\n/**\n * Validate the current CLI auth token by calling /users/me.\n *\n * Returns null only for auth failures (401/403). Re-throws network errors,\n * timeouts, and server errors so callers can handle them appropriately\n * instead of triggering an unnecessary re-login prompt.\n *\n * @returns The authenticated user if valid, null if invalid/missing.\n * @internal\n */\nexport async function validateSession(): Promise<SanityOrgUser | null> {\n const token = await getCliToken()\n if (!token) return null\n\n try {\n return await getCliUser()\n } catch (error) {\n if (isHttpError(error) && (error.statusCode === 401 || error.statusCode === 403)) {\n return null\n }\n throw error\n }\n}\n"],"names":["getCliToken","getErrorMessage","isHttpError","LoginError","getCliUser","login","LOGIN_REQUIRED_MESSAGE","ensureAuthenticated","options","user","validateSession","output","warn","telemetry","cause","statusCode","token","error"],"mappings":"AAAA,SAEEA,WAAW,QAGN,mBAAkB;AACzB,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,UAAU,QAAO,6BAA4B;AACrD,SAAQC,UAAU,QAAO,yBAAwB;AACjD,SAAQC,KAAK,QAAO,mBAAkB;AACtC,SAAQC,sBAAsB,QAAO,+BAA8B;AAEnE;;;;;;;;CAQC,GACD,OAAO,eAAeC,oBAAoBC,OAGzC;IACC,MAAMC,OAAO,MAAMC;IACnB,IAAID,MAAM,OAAOA;IAEjBD,QAAQG,MAAM,CAACC,IAAI,CAACN;IAEpB,IAAI;QACF,MAAMD,MAAM;YAACM,QAAQH,QAAQG,MAAM;YAAEE,WAAWL,QAAQK,SAAS;QAAA;IACnE,EAAE,OAAOC,OAAO;QACd,MAAM,IAAIX,WAAWF,gBAAgBa,QAAQ;YAACA;QAAK;IACrD;IAEA,IAAI;QACF,OAAO,MAAMV;IACf,EAAE,OAAOU,OAAO;QACd,IAAIZ,YAAYY,UAAWA,CAAAA,MAAMC,UAAU,KAAK,OAAOD,MAAMC,UAAU,KAAK,GAAE,GAAI;YAChF,MAAM,IAAIZ,WACR,CAAC,8CAA8C,EAAEF,gBAAgBa,QAAQ,EACzE;gBAACA;YAAK;QAEV;QACA,MAAMA;IACR;AACF;AAEA;;;;;;;;;CASC,GACD,OAAO,eAAeJ;IACpB,MAAMM,QAAQ,MAAMhB;IACpB,IAAI,CAACgB,OAAO,OAAO;IAEnB,IAAI;QACF,OAAO,MAAMZ;IACf,EAAE,OAAOa,OAAO;QACd,IAAIf,YAAYe,UAAWA,CAAAA,MAAMF,UAAU,KAAK,OAAOE,MAAMF,UAAU,KAAK,GAAE,GAAI;YAChF,OAAO;QACT;QACA,MAAME;IACR;AACF"}
|
|
@@ -49,8 +49,13 @@ const debug = subdebug('login:getProvider');
|
|
|
49
49
|
if (providers.length === 0) {
|
|
50
50
|
return undefined;
|
|
51
51
|
}
|
|
52
|
-
if (!isInteractive()
|
|
53
|
-
|
|
52
|
+
if (!isInteractive()) {
|
|
53
|
+
if (realProviderNames.length === 1) {
|
|
54
|
+
return providers.find((provider)=>provider.name === realProviderNames[0]);
|
|
55
|
+
}
|
|
56
|
+
if (realProviderNames.length > 1) {
|
|
57
|
+
throw new Error(`Multiple login providers available: ${realProviderNames.join(', ')}. ` + 'Use `--provider <name>` to select one in unattended mode.');
|
|
58
|
+
}
|
|
54
59
|
}
|
|
55
60
|
const provider = await promptForProviders(providers);
|
|
56
61
|
if (provider.name === 'sso') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/actions/auth/login/getProvider.ts"],"sourcesContent":["import {isInteractive, subdebug} from '@sanity/cli-core'\nimport {input, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\n\nimport {promptForProviders} from '../../../prompts/promptForProviders.js'\nimport {getProviders, getVercelProviderUrl} from '../../../services/auth.js'\nimport {type LoginProvider} from '../types.js'\nimport {getSSOProvider} from './getSSOProvider.js'\n\nconst debug = subdebug('login:getProvider')\n\n/**\n * Prompt the user to select a login provider, or use the specified provider if given.\n *\n * @param options - Options for the provider resolve operation\n * @returns Promise that resolves to the selected login provider\n * @internal\n */\nexport async function getProvider({\n experimental,\n orgSlug,\n specifiedProvider,\n ssoProvider,\n}: {\n experimental: boolean | undefined\n orgSlug: string | undefined\n specifiedProvider: string | undefined\n ssoProvider: string | undefined\n}): Promise<LoginProvider | undefined> {\n if (specifiedProvider === 'vercel') {\n return {\n name: 'vercel',\n title: 'Vercel',\n url: await getVercelProviderUrl(),\n }\n }\n\n let spin: SpinnerInstance | undefined\n\n try {\n if (orgSlug) {\n return getSSOProvider(orgSlug, ssoProvider)\n }\n\n spin = spinner('Fetching providers...').start()\n // Fetch and prompt for login provider to use\n let {providers} = await getProviders()\n if (experimental) {\n providers = [...providers, {name: 'sso', title: 'SSO', url: '_not_used_'}]\n }\n spin.stop()\n\n // Real providers excludes the synthetic SSO entry used by --experimental\n const realProviderNames = providers.filter((p) => p.name !== 'sso').map((p) => p.name)\n\n if (specifiedProvider) {\n const provider = providers.find((prov) => prov.name === specifiedProvider)\n if (!provider) {\n throw new Error(\n `Cannot find login provider with name \"${specifiedProvider}\". ` +\n (realProviderNames.length > 0\n ? `Available providers: ${realProviderNames.join(', ')}`\n : 'No providers are available'),\n )\n }\n return provider\n }\n\n if (providers.length === 0) {\n return undefined\n }\n\n if (!isInteractive()
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/auth/login/getProvider.ts"],"sourcesContent":["import {isInteractive, subdebug} from '@sanity/cli-core'\nimport {input, spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\n\nimport {promptForProviders} from '../../../prompts/promptForProviders.js'\nimport {getProviders, getVercelProviderUrl} from '../../../services/auth.js'\nimport {type LoginProvider} from '../types.js'\nimport {getSSOProvider} from './getSSOProvider.js'\n\nconst debug = subdebug('login:getProvider')\n\n/**\n * Prompt the user to select a login provider, or use the specified provider if given.\n *\n * @param options - Options for the provider resolve operation\n * @returns Promise that resolves to the selected login provider\n * @internal\n */\nexport async function getProvider({\n experimental,\n orgSlug,\n specifiedProvider,\n ssoProvider,\n}: {\n experimental: boolean | undefined\n orgSlug: string | undefined\n specifiedProvider: string | undefined\n ssoProvider: string | undefined\n}): Promise<LoginProvider | undefined> {\n if (specifiedProvider === 'vercel') {\n return {\n name: 'vercel',\n title: 'Vercel',\n url: await getVercelProviderUrl(),\n }\n }\n\n let spin: SpinnerInstance | undefined\n\n try {\n if (orgSlug) {\n return getSSOProvider(orgSlug, ssoProvider)\n }\n\n spin = spinner('Fetching providers...').start()\n // Fetch and prompt for login provider to use\n let {providers} = await getProviders()\n if (experimental) {\n providers = [...providers, {name: 'sso', title: 'SSO', url: '_not_used_'}]\n }\n spin.stop()\n\n // Real providers excludes the synthetic SSO entry used by --experimental\n const realProviderNames = providers.filter((p) => p.name !== 'sso').map((p) => p.name)\n\n if (specifiedProvider) {\n const provider = providers.find((prov) => prov.name === specifiedProvider)\n if (!provider) {\n throw new Error(\n `Cannot find login provider with name \"${specifiedProvider}\". ` +\n (realProviderNames.length > 0\n ? `Available providers: ${realProviderNames.join(', ')}`\n : 'No providers are available'),\n )\n }\n return provider\n }\n\n if (providers.length === 0) {\n return undefined\n }\n\n if (!isInteractive()) {\n if (realProviderNames.length === 1) {\n return providers.find((provider) => provider.name === realProviderNames[0])\n }\n\n if (realProviderNames.length > 1) {\n throw new Error(\n `Multiple login providers available: ${realProviderNames.join(', ')}. ` +\n 'Use `--provider <name>` to select one in unattended mode.',\n )\n }\n }\n\n const provider = await promptForProviders(providers)\n if (provider.name === 'sso') {\n const orgSlug = await input({message: 'Organization slug:'})\n return getSSOProvider(orgSlug)\n }\n\n return provider\n } catch (err) {\n spin?.stop()\n debug('Error retrieving providers', err)\n throw err\n }\n}\n"],"names":["isInteractive","subdebug","input","spinner","promptForProviders","getProviders","getVercelProviderUrl","getSSOProvider","debug","getProvider","experimental","orgSlug","specifiedProvider","ssoProvider","name","title","url","spin","start","providers","stop","realProviderNames","filter","p","map","provider","find","prov","Error","length","join","undefined","message","err"],"mappings":"AAAA,SAAQA,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACxD,SAAQC,KAAK,EAAEC,OAAO,QAA6B,sBAAqB;AAExE,SAAQC,kBAAkB,QAAO,yCAAwC;AACzE,SAAQC,YAAY,EAAEC,oBAAoB,QAAO,4BAA2B;AAE5E,SAAQC,cAAc,QAAO,sBAAqB;AAElD,MAAMC,QAAQP,SAAS;AAEvB;;;;;;CAMC,GACD,OAAO,eAAeQ,YAAY,EAChCC,YAAY,EACZC,OAAO,EACPC,iBAAiB,EACjBC,WAAW,EAMZ;IACC,IAAID,sBAAsB,UAAU;QAClC,OAAO;YACLE,MAAM;YACNC,OAAO;YACPC,KAAK,MAAMV;QACb;IACF;IAEA,IAAIW;IAEJ,IAAI;QACF,IAAIN,SAAS;YACX,OAAOJ,eAAeI,SAASE;QACjC;QAEAI,OAAOd,QAAQ,yBAAyBe,KAAK;QAC7C,6CAA6C;QAC7C,IAAI,EAACC,SAAS,EAAC,GAAG,MAAMd;QACxB,IAAIK,cAAc;YAChBS,YAAY;mBAAIA;gBAAW;oBAACL,MAAM;oBAAOC,OAAO;oBAAOC,KAAK;gBAAY;aAAE;QAC5E;QACAC,KAAKG,IAAI;QAET,yEAAyE;QACzE,MAAMC,oBAAoBF,UAAUG,MAAM,CAAC,CAACC,IAAMA,EAAET,IAAI,KAAK,OAAOU,GAAG,CAAC,CAACD,IAAMA,EAAET,IAAI;QAErF,IAAIF,mBAAmB;YACrB,MAAMa,WAAWN,UAAUO,IAAI,CAAC,CAACC,OAASA,KAAKb,IAAI,KAAKF;YACxD,IAAI,CAACa,UAAU;gBACb,MAAM,IAAIG,MACR,CAAC,sCAAsC,EAAEhB,kBAAkB,GAAG,CAAC,GAC5DS,CAAAA,kBAAkBQ,MAAM,GAAG,IACxB,CAAC,qBAAqB,EAAER,kBAAkBS,IAAI,CAAC,OAAO,GACtD,4BAA2B;YAErC;YACA,OAAOL;QACT;QAEA,IAAIN,UAAUU,MAAM,KAAK,GAAG;YAC1B,OAAOE;QACT;QAEA,IAAI,CAAC/B,iBAAiB;YACpB,IAAIqB,kBAAkBQ,MAAM,KAAK,GAAG;gBAClC,OAAOV,UAAUO,IAAI,CAAC,CAACD,WAAaA,SAASX,IAAI,KAAKO,iBAAiB,CAAC,EAAE;YAC5E;YAEA,IAAIA,kBAAkBQ,MAAM,GAAG,GAAG;gBAChC,MAAM,IAAID,MACR,CAAC,oCAAoC,EAAEP,kBAAkBS,IAAI,CAAC,MAAM,EAAE,CAAC,GACrE;YAEN;QACF;QAEA,MAAML,WAAW,MAAMrB,mBAAmBe;QAC1C,IAAIM,SAASX,IAAI,KAAK,OAAO;YAC3B,MAAMH,UAAU,MAAMT,MAAM;gBAAC8B,SAAS;YAAoB;YAC1D,OAAOzB,eAAeI;QACxB;QAEA,OAAOc;IACT,EAAE,OAAOQ,KAAK;QACZhB,MAAMG;QACNZ,MAAM,8BAA8ByB;QACpC,MAAMA;IACR;AACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const LOGIN_PROVIDER_IDS = [
|
|
2
|
+
'google',
|
|
3
|
+
'github',
|
|
4
|
+
'sanity',
|
|
5
|
+
'vercel'
|
|
6
|
+
];
|
|
7
|
+
export const LOGIN_REQUIRED_MESSAGE = [
|
|
8
|
+
'No valid authentication credentials found.',
|
|
9
|
+
'',
|
|
10
|
+
'Authenticate with one of these commands:',
|
|
11
|
+
' echo "$TOKEN" | sanity login --with-token',
|
|
12
|
+
' sanity login --provider <providerId> --no-open',
|
|
13
|
+
` Provider IDs: ${LOGIN_PROVIDER_IDS.join(', ')}`,
|
|
14
|
+
' sanity login --sso <organizationSlug> --no-open',
|
|
15
|
+
'',
|
|
16
|
+
'`--no-open` prints a login URL instead of opening a browser.'
|
|
17
|
+
].join('\n');
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=loginInstructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/auth/login/loginInstructions.ts"],"sourcesContent":["export const LOGIN_PROVIDER_IDS = ['google', 'github', 'sanity', 'vercel'] as const\n\nexport const LOGIN_REQUIRED_MESSAGE = [\n 'No valid authentication credentials found.',\n '',\n 'Authenticate with one of these commands:',\n ' echo \"$TOKEN\" | sanity login --with-token',\n ' sanity login --provider <providerId> --no-open',\n ` Provider IDs: ${LOGIN_PROVIDER_IDS.join(', ')}`,\n ' sanity login --sso <organizationSlug> --no-open',\n '',\n '`--no-open` prints a login URL instead of opening a browser.',\n].join('\\n')\n"],"names":["LOGIN_PROVIDER_IDS","LOGIN_REQUIRED_MESSAGE","join"],"mappings":"AAAA,OAAO,MAAMA,qBAAqB;IAAC;IAAU;IAAU;IAAU;CAAS,CAAS;AAEnF,OAAO,MAAMC,yBAAyB;IACpC;IACA;IACA;IACA;IACA;IACA,CAAC,kBAAkB,EAAED,mBAAmBE,IAAI,CAAC,OAAO;IACpD;IACA;IACA;CACD,CAACA,IAAI,CAAC,MAAK"}
|
|
@@ -16,7 +16,7 @@ const debug = subdebug('dataset:create');
|
|
|
16
16
|
* @returns Promise resolving when dataset is created
|
|
17
17
|
* @throws Error if dataset creation fails
|
|
18
18
|
*/ export async function createDataset(options) {
|
|
19
|
-
const { datasetName, embeddings, embeddingsProjection, forcePublic = false, isUnattended = false, output, projectFeatures, projectId, visibility } = options;
|
|
19
|
+
const { datasetName, embeddings, embeddingsProjection, forcePublic = false, isUnattended = false, output, projectFeatures, projectId, silent = false, visibility } = options;
|
|
20
20
|
const canCreatePrivate = projectFeatures.includes('privateDataset') && !forcePublic;
|
|
21
21
|
// Determine the appropriate ACL mode
|
|
22
22
|
const aclMode = await determineDatasetAclMode({
|
|
@@ -42,7 +42,7 @@ const debug = subdebug('dataset:create');
|
|
|
42
42
|
projectId
|
|
43
43
|
});
|
|
44
44
|
spin.succeed();
|
|
45
|
-
output.log(`Dataset created successfully`);
|
|
45
|
+
if (!silent) output.log(`Dataset created successfully`);
|
|
46
46
|
return newDataset;
|
|
47
47
|
} catch (error) {
|
|
48
48
|
debug('Error creating dataset', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/dataset/create.ts"],"sourcesContent":["import {type Output, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type DatasetAclMode, DatasetResponse} from '@sanity/client'\n\nimport {createDataset as createDatasetService} from '../../services/datasets.js'\nimport {validateProjection} from '../../util/validateProjection.js'\nimport {determineDatasetAclMode} from './determineDatasetAclMode.js'\n\nconst debug = subdebug('dataset:create')\n\n/**\n * Options for creating a dataset\n */\ninterface CreateDatasetOptions {\n /**\n * Name of the dataset to create\n */\n datasetName: string\n\n /**\n * Output instance for logging\n */\n output: Output\n\n /**\n * Array of project features to determine capabilities\n * Used to check if private datasets are available\n */\n projectFeatures: string[]\n\n /**\n * Project ID where the dataset will be created\n */\n projectId: string\n\n /**\n * Whether to enable embeddings for the new dataset\n */\n embeddings?: boolean\n\n /**\n * GROQ projection for embeddings indexing (e.g. \"\\{ title, body \\}\")\n * Only used when embeddings is true\n */\n embeddingsProjection?: string\n\n /**\n * Whether to force disable private dataset creation\n * Used when default config is selected (which forces public datasets)\n */\n forcePublic?: boolean\n\n /**\n * Whether to run in unattended mode (no prompts)\n */\n isUnattended?: boolean\n\n /**\n * Requested visibility mode from flags/options\n */\n visibility?: string\n}\n\n/**\n * Creates a new dataset with the appropriate ACL mode.\n *\n * This action handles the business logic for:\n * - Determining the appropriate ACL mode based on project capabilities\n * - Creating the dataset via the service layer\n * - Handling errors and providing user feedback\n *\n * @param options - Configuration options\n * @returns Promise resolving when dataset is created\n * @throws Error if dataset creation fails\n */\nexport async function createDataset(options: CreateDatasetOptions): Promise<DatasetResponse> {\n const {\n datasetName,\n embeddings,\n embeddingsProjection,\n forcePublic = false,\n isUnattended = false,\n output,\n projectFeatures,\n projectId,\n visibility,\n } = options\n\n const canCreatePrivate = projectFeatures.includes('privateDataset') && !forcePublic\n\n // Determine the appropriate ACL mode\n const aclMode: DatasetAclMode = await determineDatasetAclMode({\n canCreatePrivate,\n isUnattended,\n output,\n visibility,\n })\n\n if (embeddingsProjection) {\n validateProjection(embeddingsProjection)\n }\n\n try {\n const spin = spinner('Creating dataset').start()\n const newDataset = await createDatasetService({\n aclMode,\n datasetName,\n embeddings: embeddings\n ? {enabled: true, ...(embeddingsProjection ? {projection: embeddingsProjection} : {})}\n : undefined,\n projectId,\n })\n spin.succeed()\n output.log(`Dataset created successfully`)\n return newDataset\n } catch (error) {\n debug('Error creating dataset', {datasetName, error})\n throw error\n }\n}\n"],"names":["subdebug","spinner","createDataset","createDatasetService","validateProjection","determineDatasetAclMode","debug","options","datasetName","embeddings","embeddingsProjection","forcePublic","isUnattended","output","projectFeatures","projectId","visibility","canCreatePrivate","includes","aclMode","spin","start","newDataset","enabled","projection","undefined","succeed","log","error"],"mappings":"AAAA,SAAqBA,QAAQ,QAAO,mBAAkB;AACtD,SAAQC,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,iBAAiBC,oBAAoB,QAAO,6BAA4B;AAChF,SAAQC,kBAAkB,QAAO,mCAAkC;AACnE,SAAQC,uBAAuB,QAAO,+BAA8B;AAEpE,MAAMC,QAAQN,SAAS;
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/dataset/create.ts"],"sourcesContent":["import {type Output, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type DatasetAclMode, DatasetResponse} from '@sanity/client'\n\nimport {createDataset as createDatasetService} from '../../services/datasets.js'\nimport {validateProjection} from '../../util/validateProjection.js'\nimport {determineDatasetAclMode} from './determineDatasetAclMode.js'\n\nconst debug = subdebug('dataset:create')\n\n/**\n * Options for creating a dataset\n */\ninterface CreateDatasetOptions {\n /**\n * Name of the dataset to create\n */\n datasetName: string\n\n /**\n * Output instance for logging\n */\n output: Output\n\n /**\n * Array of project features to determine capabilities\n * Used to check if private datasets are available\n */\n projectFeatures: string[]\n\n /**\n * Project ID where the dataset will be created\n */\n projectId: string\n\n /**\n * Whether to enable embeddings for the new dataset\n */\n embeddings?: boolean\n\n /**\n * GROQ projection for embeddings indexing (e.g. \"\\{ title, body \\}\")\n * Only used when embeddings is true\n */\n embeddingsProjection?: string\n\n /**\n * Whether to force disable private dataset creation\n * Used when default config is selected (which forces public datasets)\n */\n forcePublic?: boolean\n\n /**\n * Whether to run in unattended mode (no prompts)\n */\n isUnattended?: boolean\n\n /**\n * Whether to omit human-readable success output\n */\n silent?: boolean\n\n /**\n * Requested visibility mode from flags/options\n */\n visibility?: string\n}\n\n/**\n * Creates a new dataset with the appropriate ACL mode.\n *\n * This action handles the business logic for:\n * - Determining the appropriate ACL mode based on project capabilities\n * - Creating the dataset via the service layer\n * - Handling errors and providing user feedback\n *\n * @param options - Configuration options\n * @returns Promise resolving when dataset is created\n * @throws Error if dataset creation fails\n */\nexport async function createDataset(options: CreateDatasetOptions): Promise<DatasetResponse> {\n const {\n datasetName,\n embeddings,\n embeddingsProjection,\n forcePublic = false,\n isUnattended = false,\n output,\n projectFeatures,\n projectId,\n silent = false,\n visibility,\n } = options\n\n const canCreatePrivate = projectFeatures.includes('privateDataset') && !forcePublic\n\n // Determine the appropriate ACL mode\n const aclMode: DatasetAclMode = await determineDatasetAclMode({\n canCreatePrivate,\n isUnattended,\n output,\n visibility,\n })\n\n if (embeddingsProjection) {\n validateProjection(embeddingsProjection)\n }\n\n try {\n const spin = spinner('Creating dataset').start()\n const newDataset = await createDatasetService({\n aclMode,\n datasetName,\n embeddings: embeddings\n ? {enabled: true, ...(embeddingsProjection ? {projection: embeddingsProjection} : {})}\n : undefined,\n projectId,\n })\n spin.succeed()\n if (!silent) output.log(`Dataset created successfully`)\n return newDataset\n } catch (error) {\n debug('Error creating dataset', {datasetName, error})\n throw error\n }\n}\n"],"names":["subdebug","spinner","createDataset","createDatasetService","validateProjection","determineDatasetAclMode","debug","options","datasetName","embeddings","embeddingsProjection","forcePublic","isUnattended","output","projectFeatures","projectId","silent","visibility","canCreatePrivate","includes","aclMode","spin","start","newDataset","enabled","projection","undefined","succeed","log","error"],"mappings":"AAAA,SAAqBA,QAAQ,QAAO,mBAAkB;AACtD,SAAQC,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,iBAAiBC,oBAAoB,QAAO,6BAA4B;AAChF,SAAQC,kBAAkB,QAAO,mCAAkC;AACnE,SAAQC,uBAAuB,QAAO,+BAA8B;AAEpE,MAAMC,QAAQN,SAAS;AA4DvB;;;;;;;;;;;CAWC,GACD,OAAO,eAAeE,cAAcK,OAA6B;IAC/D,MAAM,EACJC,WAAW,EACXC,UAAU,EACVC,oBAAoB,EACpBC,cAAc,KAAK,EACnBC,eAAe,KAAK,EACpBC,MAAM,EACNC,eAAe,EACfC,SAAS,EACTC,SAAS,KAAK,EACdC,UAAU,EACX,GAAGV;IAEJ,MAAMW,mBAAmBJ,gBAAgBK,QAAQ,CAAC,qBAAqB,CAACR;IAExE,qCAAqC;IACrC,MAAMS,UAA0B,MAAMf,wBAAwB;QAC5Da;QACAN;QACAC;QACAI;IACF;IAEA,IAAIP,sBAAsB;QACxBN,mBAAmBM;IACrB;IAEA,IAAI;QACF,MAAMW,OAAOpB,QAAQ,oBAAoBqB,KAAK;QAC9C,MAAMC,aAAa,MAAMpB,qBAAqB;YAC5CiB;YACAZ;YACAC,YAAYA,aACR;gBAACe,SAAS;gBAAM,GAAId,uBAAuB;oBAACe,YAAYf;gBAAoB,IAAI,CAAC,CAAC;YAAC,IACnFgB;YACJX;QACF;QACAM,KAAKM,OAAO;QACZ,IAAI,CAACX,QAAQH,OAAOe,GAAG,CAAC,CAAC,4BAA4B,CAAC;QACtD,OAAOL;IACT,EAAE,OAAOM,OAAO;QACdvB,MAAM,0BAA0B;YAACE;YAAaqB;QAAK;QACnD,MAAMA;IACR;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { exitCodes } from '@sanity/cli-core';
|
|
1
2
|
import { promptForDataset } from '../../prompts/promptForDataset.js';
|
|
2
3
|
import { listDatasets } from '../../services/datasets.js';
|
|
3
4
|
import { assertDatasetExists } from '../backup/assertDatasetExist.js';
|
|
@@ -5,7 +6,12 @@ import { assertDatasetExists } from '../backup/assertDatasetExist.js';
|
|
|
5
6
|
* Lists datasets for a project, validates the given dataset name (or prompts
|
|
6
7
|
* the user to pick one), and returns the resolved name together with the full
|
|
7
8
|
* dataset list.
|
|
8
|
-
*/ export async function resolveDataset({ dataset, output, projectId }) {
|
|
9
|
+
*/ export async function resolveDataset({ dataset, isUnattended, output, projectId }) {
|
|
10
|
+
if (!dataset && isUnattended) {
|
|
11
|
+
output.error('Dataset name is required. Pass it as the `<dataset>` argument.', {
|
|
12
|
+
exit: exitCodes.USAGE_ERROR
|
|
13
|
+
});
|
|
14
|
+
}
|
|
9
15
|
const datasets = await listDatasets(projectId);
|
|
10
16
|
if (datasets.length === 0) {
|
|
11
17
|
throw new Error('No datasets found in this project.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/dataset/resolveDataset.ts"],"sourcesContent":["import {type Output} from '@sanity/cli-core'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {assertDatasetExists} from '../backup/assertDatasetExist.js'\n\ninterface ResolveDatasetOptions {\n /** Output to use for user-facing messages from the calling command */\n output: Output\n\n projectId: string\n\n dataset?: string\n}\n\ninterface ResolveDatasetResult {\n dataset: string\n datasets: DatasetsResponse\n}\n\n/**\n * Lists datasets for a project, validates the given dataset name (or prompts\n * the user to pick one), and returns the resolved name together with the full\n * dataset list.\n */\nexport async function resolveDataset({\n dataset,\n output,\n projectId,\n}: ResolveDatasetOptions): Promise<ResolveDatasetResult> {\n const datasets = await listDatasets(projectId)\n\n if (datasets.length === 0) {\n throw new Error('No datasets found in this project.')\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset, output)\n } else {\n dataset = await promptForDataset({datasets})\n }\n\n return {dataset, datasets}\n}\n"],"names":["promptForDataset","listDatasets","assertDatasetExists","resolveDataset","dataset","output","projectId","datasets","length","Error"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/dataset/resolveDataset.ts"],"sourcesContent":["import {exitCodes, type Output} from '@sanity/cli-core'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {assertDatasetExists} from '../backup/assertDatasetExist.js'\n\ninterface ResolveDatasetOptions {\n /** Output to use for user-facing messages from the calling command */\n output: Output\n\n projectId: string\n\n dataset?: string\n isUnattended?: boolean\n}\n\ninterface ResolveDatasetResult {\n dataset: string\n datasets: DatasetsResponse\n}\n\n/**\n * Lists datasets for a project, validates the given dataset name (or prompts\n * the user to pick one), and returns the resolved name together with the full\n * dataset list.\n */\nexport async function resolveDataset({\n dataset,\n isUnattended,\n output,\n projectId,\n}: ResolveDatasetOptions): Promise<ResolveDatasetResult> {\n if (!dataset && isUnattended) {\n output.error('Dataset name is required. Pass it as the `<dataset>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const datasets = await listDatasets(projectId)\n\n if (datasets.length === 0) {\n throw new Error('No datasets found in this project.')\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset, output)\n } else {\n dataset = await promptForDataset({datasets})\n }\n\n return {dataset, datasets}\n}\n"],"names":["exitCodes","promptForDataset","listDatasets","assertDatasetExists","resolveDataset","dataset","isUnattended","output","projectId","error","exit","USAGE_ERROR","datasets","length","Error"],"mappings":"AAAA,SAAQA,SAAS,QAAoB,mBAAkB;AAGvD,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,YAAY,QAAO,6BAA4B;AACvD,SAAQC,mBAAmB,QAAO,kCAAiC;AAiBnE;;;;CAIC,GACD,OAAO,eAAeC,eAAe,EACnCC,OAAO,EACPC,YAAY,EACZC,MAAM,EACNC,SAAS,EACa;IACtB,IAAI,CAACH,WAAWC,cAAc;QAC5BC,OAAOE,KAAK,CAAC,kEAAkE;YAC7EC,MAAMV,UAAUW,WAAW;QAC7B;IACF;IAEA,MAAMC,WAAW,MAAMV,aAAaM;IAEpC,IAAII,SAASC,MAAM,KAAK,GAAG;QACzB,MAAM,IAAIC,MAAM;IAClB;IAEA,IAAIT,SAAS;QACXF,oBAAoBS,UAAUP,SAASE;IACzC,OAAO;QACLF,UAAU,MAAMJ,iBAAiB;YAACW;QAAQ;IAC5C;IAEA,OAAO;QAACP;QAASO;IAAQ;AAC3B"}
|
|
@@ -78,7 +78,7 @@ export async function createStudioUserApplication(options) {
|
|
|
78
78
|
});
|
|
79
79
|
return await promise;
|
|
80
80
|
}
|
|
81
|
-
export async function createUserApplication(organizationId, title) {
|
|
81
|
+
export async function createUserApplication(organizationId, title, visibility) {
|
|
82
82
|
if (!organizationId) {
|
|
83
83
|
throw new Error(NO_ORGANIZATION_ID);
|
|
84
84
|
}
|
|
@@ -86,9 +86,9 @@ export async function createUserApplication(organizationId, title) {
|
|
|
86
86
|
message: 'Enter a title for your application:',
|
|
87
87
|
validate: (value)=>value.length > 0 || 'Title is required'
|
|
88
88
|
});
|
|
89
|
-
return tryCreateApp(resolvedTitle, organizationId);
|
|
89
|
+
return tryCreateApp(resolvedTitle, organizationId, visibility);
|
|
90
90
|
}
|
|
91
|
-
const tryCreateApp = async (title, organizationId)=>{
|
|
91
|
+
const tryCreateApp = async (title, organizationId, visibility)=>{
|
|
92
92
|
// we will likely prepend this with an org ID or other parameter in the future
|
|
93
93
|
const appHost = generateAppSlug();
|
|
94
94
|
const spin = spinner('Creating application').start();
|
|
@@ -99,7 +99,10 @@ const tryCreateApp = async (title, organizationId)=>{
|
|
|
99
99
|
appHost,
|
|
100
100
|
title,
|
|
101
101
|
type: 'coreApp',
|
|
102
|
-
urlType: 'internal'
|
|
102
|
+
urlType: 'internal',
|
|
103
|
+
...visibility ? {
|
|
104
|
+
dashboardStatus: visibility
|
|
105
|
+
} : {}
|
|
103
106
|
},
|
|
104
107
|
organizationId
|
|
105
108
|
});
|
|
@@ -112,7 +115,7 @@ const tryCreateApp = async (title, organizationId)=>{
|
|
|
112
115
|
409
|
|
113
116
|
].includes(e?.statusCode)) {
|
|
114
117
|
deployDebug('App host taken, retrying with new host');
|
|
115
|
-
return tryCreateApp(title, organizationId);
|
|
118
|
+
return tryCreateApp(title, organizationId, visibility);
|
|
116
119
|
}
|
|
117
120
|
spin.fail();
|
|
118
121
|
deployDebug('Error creating core application', e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/createUserApplication.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {input, spinner} from '@sanity/cli-core/ux'\nimport {customAlphabet} from 'nanoid'\n\nimport {\n createUserApplication as createUserApplicationRequest,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {deployDebug} from './deployDebug.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.js'\n\nconst LETTERS = 'abcdefghijklmnopqrstuvwxyz'\n\n// appHosts have some restrictions (no uppercase, must start with a letter)\nexport function generateAppSlug(): string {\n const firstChar = customAlphabet(LETTERS, 1)()\n const rest = customAlphabet(`${LETTERS}0123456789`, 11)()\n return `${firstChar}${rest}`\n}\n\n// TODO: replace with `Promise.withResolvers()` once it lands in node 22\nfunction promiseWithResolvers<T>() {\n let resolve!: (t: T) => void\n let reject!: (err: unknown) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n return {promise, reject, resolve}\n}\n\ninterface CreateStudioUserApplicationOptions {\n projectId: string\n\n title?: string\n urlType?: 'external' | 'internal'\n}\n\nexport async function createStudioUserApplication(options: CreateStudioUserApplicationOptions) {\n const {projectId, title, urlType = 'internal'} = options\n const {promise, resolve} = promiseWithResolvers<UserApplication>()\n\n const isExternal = urlType === 'external'\n\n await input({\n message: isExternal ? 'Studio URL (https://...):' : 'Studio hostname (<value>.sanity.studio):',\n // if a string is returned here, it is relayed to the user and prompt allows\n // the user to try again until this function returns true\n validate: async (inp: string) => {\n let appHost: string\n\n if (isExternal) {\n const normalized = normalizeUrl(inp)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n return validation\n }\n appHost = normalized\n } else {\n appHost = inp.replace(/\\.sanity\\.studio$/i, '')\n }\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'studio',\n body: {appHost, title, type: 'studio', urlType},\n projectId,\n })\n resolve(response)\n return true\n } catch (e) {\n // if the name is taken, it should return a 409 so we relay to the user\n if ([402, 409].includes(e?.statusCode)) {\n return e?.response?.body?.message || 'Bad request' // just in case\n }\n\n deployDebug('Error creating user application', e)\n // otherwise, it's a fatal error\n throw new CLIError('Error creating user application', {exit: 1})\n }\n },\n })\n\n return await promise\n}\n\nexport async function createUserApplication(\n organizationId?: string,\n title?: string,\n): Promise<UserApplicationResolved> {\n if (!organizationId) {\n throw new Error(NO_ORGANIZATION_ID)\n }\n\n const resolvedTitle =\n title ??\n (await input({\n message: 'Enter a title for your application:',\n validate: (value: string) => value.length > 0 || 'Title is required',\n }))\n\n return tryCreateApp(resolvedTitle, organizationId)\n}\n\nconst tryCreateApp = async (title: string, organizationId: string) => {\n // we will likely prepend this with an org ID or other parameter in the future\n const appHost = generateAppSlug()\n\n const spin = spinner('Creating application').start()\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'coreApp',\n body: {appHost
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/createUserApplication.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {type AppVisibility} from '@sanity/cli-core'\nimport {input, spinner} from '@sanity/cli-core/ux'\nimport {customAlphabet} from 'nanoid'\n\nimport {\n createUserApplication as createUserApplicationRequest,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {deployDebug} from './deployDebug.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.js'\n\nconst LETTERS = 'abcdefghijklmnopqrstuvwxyz'\n\n// appHosts have some restrictions (no uppercase, must start with a letter)\nexport function generateAppSlug(): string {\n const firstChar = customAlphabet(LETTERS, 1)()\n const rest = customAlphabet(`${LETTERS}0123456789`, 11)()\n return `${firstChar}${rest}`\n}\n\n// TODO: replace with `Promise.withResolvers()` once it lands in node 22\nfunction promiseWithResolvers<T>() {\n let resolve!: (t: T) => void\n let reject!: (err: unknown) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n return {promise, reject, resolve}\n}\n\ninterface CreateStudioUserApplicationOptions {\n projectId: string\n\n title?: string\n urlType?: 'external' | 'internal'\n}\n\nexport async function createStudioUserApplication(options: CreateStudioUserApplicationOptions) {\n const {projectId, title, urlType = 'internal'} = options\n const {promise, resolve} = promiseWithResolvers<UserApplication>()\n\n const isExternal = urlType === 'external'\n\n await input({\n message: isExternal ? 'Studio URL (https://...):' : 'Studio hostname (<value>.sanity.studio):',\n // if a string is returned here, it is relayed to the user and prompt allows\n // the user to try again until this function returns true\n validate: async (inp: string) => {\n let appHost: string\n\n if (isExternal) {\n const normalized = normalizeUrl(inp)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n return validation\n }\n appHost = normalized\n } else {\n appHost = inp.replace(/\\.sanity\\.studio$/i, '')\n }\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'studio',\n body: {appHost, title, type: 'studio', urlType},\n projectId,\n })\n resolve(response)\n return true\n } catch (e) {\n // if the name is taken, it should return a 409 so we relay to the user\n if ([402, 409].includes(e?.statusCode)) {\n return e?.response?.body?.message || 'Bad request' // just in case\n }\n\n deployDebug('Error creating user application', e)\n // otherwise, it's a fatal error\n throw new CLIError('Error creating user application', {exit: 1})\n }\n },\n })\n\n return await promise\n}\n\nexport async function createUserApplication(\n organizationId?: string,\n title?: string,\n visibility?: AppVisibility,\n): Promise<UserApplicationResolved> {\n if (!organizationId) {\n throw new Error(NO_ORGANIZATION_ID)\n }\n\n const resolvedTitle =\n title ??\n (await input({\n message: 'Enter a title for your application:',\n validate: (value: string) => value.length > 0 || 'Title is required',\n }))\n\n return tryCreateApp(resolvedTitle, organizationId, visibility)\n}\n\nconst tryCreateApp = async (title: string, organizationId: string, visibility?: AppVisibility) => {\n // we will likely prepend this with an org ID or other parameter in the future\n const appHost = generateAppSlug()\n\n const spin = spinner('Creating application').start()\n\n try {\n const response = await createUserApplicationRequest({\n appType: 'coreApp',\n body: {\n appHost,\n title,\n type: 'coreApp',\n urlType: 'internal',\n ...(visibility ? {dashboardStatus: visibility} : {}),\n },\n organizationId,\n })\n\n spin.succeed()\n return response\n } catch (e) {\n // if the name is taken, generate a new one and try again\n if ([402, 409].includes(e?.statusCode)) {\n deployDebug('App host taken, retrying with new host')\n return tryCreateApp(title, organizationId, visibility)\n }\n\n spin.fail()\n\n deployDebug('Error creating core application', e)\n throw e\n }\n}\n"],"names":["CLIError","input","spinner","customAlphabet","createUserApplication","createUserApplicationRequest","NO_ORGANIZATION_ID","deployDebug","normalizeUrl","validateUrl","LETTERS","generateAppSlug","firstChar","rest","promiseWithResolvers","resolve","reject","promise","Promise","res","rej","createStudioUserApplication","options","projectId","title","urlType","isExternal","message","validate","inp","appHost","normalized","validation","replace","response","appType","body","type","e","includes","statusCode","exit","organizationId","visibility","Error","resolvedTitle","value","length","tryCreateApp","spin","start","dashboardStatus","succeed","fail"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,qBAAoB;AAE3C,SAAQC,KAAK,EAAEC,OAAO,QAAO,sBAAqB;AAClD,SAAQC,cAAc,QAAO,SAAQ;AAErC,SACEC,yBAAyBC,4BAA4B,QAGhD,qCAAoC;AAC3C,SAAQC,kBAAkB,QAAO,8BAA6B;AAC9D,SAAQC,WAAW,QAAO,mBAAkB;AAC5C,SAAQC,YAAY,EAAEC,WAAW,QAAO,gBAAe;AAEvD,MAAMC,UAAU;AAEhB,2EAA2E;AAC3E,OAAO,SAASC;IACd,MAAMC,YAAYT,eAAeO,SAAS;IAC1C,MAAMG,OAAOV,eAAe,GAAGO,QAAQ,UAAU,CAAC,EAAE;IACpD,OAAO,GAAGE,YAAYC,MAAM;AAC9B;AAEA,wEAAwE;AACxE,SAASC;IACP,IAAIC;IACJ,IAAIC;IACJ,MAAMC,UAAU,IAAIC,QAAW,CAACC,KAAKC;QACnCL,UAAUI;QACVH,SAASI;IACX;IACA,OAAO;QAACH;QAASD;QAAQD;IAAO;AAClC;AASA,OAAO,eAAeM,4BAA4BC,OAA2C;IAC3F,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAEC,UAAU,UAAU,EAAC,GAAGH;IACjD,MAAM,EAACL,OAAO,EAAEF,OAAO,EAAC,GAAGD;IAE3B,MAAMY,aAAaD,YAAY;IAE/B,MAAMxB,MAAM;QACV0B,SAASD,aAAa,8BAA8B;QACpD,4EAA4E;QAC5E,yDAAyD;QACzDE,UAAU,OAAOC;YACf,IAAIC;YAEJ,IAAIJ,YAAY;gBACd,MAAMK,aAAavB,aAAaqB;gBAChC,MAAMG,aAAavB,YAAYsB;gBAC/B,IAAIC,eAAe,MAAM;oBACvB,OAAOA;gBACT;gBACAF,UAAUC;YACZ,OAAO;gBACLD,UAAUD,IAAII,OAAO,CAAC,sBAAsB;YAC9C;YAEA,IAAI;gBACF,MAAMC,WAAW,MAAM7B,6BAA6B;oBAClD8B,SAAS;oBACTC,MAAM;wBAACN;wBAASN;wBAAOa,MAAM;wBAAUZ;oBAAO;oBAC9CF;gBACF;gBACAR,QAAQmB;gBACR,OAAO;YACT,EAAE,OAAOI,GAAG;gBACV,uEAAuE;gBACvE,IAAI;oBAAC;oBAAK;iBAAI,CAACC,QAAQ,CAACD,GAAGE,aAAa;oBACtC,OAAOF,GAAGJ,UAAUE,MAAMT,WAAW,cAAc,eAAe;;gBACpE;gBAEApB,YAAY,mCAAmC+B;gBAC/C,gCAAgC;gBAChC,MAAM,IAAItC,SAAS,mCAAmC;oBAACyC,MAAM;gBAAC;YAChE;QACF;IACF;IAEA,OAAO,MAAMxB;AACf;AAEA,OAAO,eAAeb,sBACpBsC,cAAuB,EACvBlB,KAAc,EACdmB,UAA0B;IAE1B,IAAI,CAACD,gBAAgB;QACnB,MAAM,IAAIE,MAAMtC;IAClB;IAEA,MAAMuC,gBACJrB,SACC,MAAMvB,MAAM;QACX0B,SAAS;QACTC,UAAU,CAACkB,QAAkBA,MAAMC,MAAM,GAAG,KAAK;IACnD;IAEF,OAAOC,aAAaH,eAAeH,gBAAgBC;AACrD;AAEA,MAAMK,eAAe,OAAOxB,OAAekB,gBAAwBC;IACjE,8EAA8E;IAC9E,MAAMb,UAAUnB;IAEhB,MAAMsC,OAAO/C,QAAQ,wBAAwBgD,KAAK;IAElD,IAAI;QACF,MAAMhB,WAAW,MAAM7B,6BAA6B;YAClD8B,SAAS;YACTC,MAAM;gBACJN;gBACAN;gBACAa,MAAM;gBACNZ,SAAS;gBACT,GAAIkB,aAAa;oBAACQ,iBAAiBR;gBAAU,IAAI,CAAC,CAAC;YACrD;YACAD;QACF;QAEAO,KAAKG,OAAO;QACZ,OAAOlB;IACT,EAAE,OAAOI,GAAG;QACV,yDAAyD;QACzD,IAAI;YAAC;YAAK;SAAI,CAACC,QAAQ,CAACD,GAAGE,aAAa;YACtCjC,YAAY;YACZ,OAAOyC,aAAaxB,OAAOkB,gBAAgBC;QAC7C;QAEAM,KAAKI,IAAI;QAET9C,YAAY,mCAAmC+B;QAC/C,MAAMA;IACR;AACF"}
|