@sanity/cli 8.6.0 → 8.7.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 +522 -40
- package/dist/commands/backups/list.js +1 -1
- package/dist/commands/backups/list.js.map +1 -1
- package/dist/commands/datasets/copy.js +1 -1
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/util/extractDocumentsFromNdjsonOrTarball.js.map +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +14 -14
- package/dist/util/dates.js +0 -125
- package/dist/util/dates.js.map +0 -1
package/README.md
CHANGED
|
@@ -126,6 +126,21 @@ Code for sanity cli
|
|
|
126
126
|
- [`sanity users invite [EMAIL]`](#sanity-users-invite-email)
|
|
127
127
|
- [`sanity users list`](#sanity-users-list)
|
|
128
128
|
- [`sanity versions`](#sanity-versions)
|
|
129
|
+
- [`sanity workflows abort INSTANCEID`](#sanity-workflows-abort-instanceid)
|
|
130
|
+
- [`sanity workflows definition delete NAME`](#sanity-workflows-definition-delete-name)
|
|
131
|
+
- [`sanity workflows definition diff NAME`](#sanity-workflows-definition-diff-name)
|
|
132
|
+
- [`sanity workflows definition list`](#sanity-workflows-definition-list)
|
|
133
|
+
- [`sanity workflows definition show NAME`](#sanity-workflows-definition-show-name)
|
|
134
|
+
- [`sanity workflows deploy`](#sanity-workflows-deploy)
|
|
135
|
+
- [`sanity workflows diagnose INSTANCEID`](#sanity-workflows-diagnose-instanceid)
|
|
136
|
+
- [`sanity workflows fire-action INSTANCEID`](#sanity-workflows-fire-action-instanceid)
|
|
137
|
+
- [`sanity workflows list`](#sanity-workflows-list)
|
|
138
|
+
- [`sanity workflows nuke`](#sanity-workflows-nuke)
|
|
139
|
+
- [`sanity workflows reset-activity INSTANCEID ACTIVITY`](#sanity-workflows-reset-activity-instanceid-activity)
|
|
140
|
+
- [`sanity workflows set-stage INSTANCEID`](#sanity-workflows-set-stage-instanceid)
|
|
141
|
+
- [`sanity workflows show INSTANCEID`](#sanity-workflows-show-instanceid)
|
|
142
|
+
- [`sanity workflows start NAME`](#sanity-workflows-start-name)
|
|
143
|
+
- [`sanity workflows tail INSTANCEID`](#sanity-workflows-tail-instanceid)
|
|
129
144
|
|
|
130
145
|
## `sanity api ENDPOINT`
|
|
131
146
|
|
|
@@ -392,7 +407,7 @@ EXAMPLES
|
|
|
392
407
|
USAGE
|
|
393
408
|
$ sanity blueprints add TYPE [--json] [--example <value> | -n <value> | --fn-type
|
|
394
409
|
document-publish|document-create|document-delete|document-update|media-library-asset-create|media-library-asset-dele
|
|
395
|
-
te|media-library-asset-update|scheduled-function|sync-tag-invalidate... | --language ts|js | --javascript |
|
|
410
|
+
te|media-library-asset-update|pub-sub|scheduled-function|sync-tag-invalidate... | --language ts|js | --javascript |
|
|
396
411
|
--fn-helpers | --fn-installer skip|npm|pnpm|yarn] [-i | ]
|
|
397
412
|
|
|
398
413
|
ARGUMENTS
|
|
@@ -409,8 +424,8 @@ FLAGS
|
|
|
409
424
|
--fn-type=<option>... Document change event(s) that should trigger the function; you can specify multiple
|
|
410
425
|
events by specifying this flag multiple times
|
|
411
426
|
<options: document-publish|document-create|document-delete|document-update|media-library-
|
|
412
|
-
asset-create|media-library-asset-delete|media-library-asset-update|scheduled-
|
|
413
|
-
|
|
427
|
+
asset-create|media-library-asset-delete|media-library-asset-update|pub-sub|scheduled-func
|
|
428
|
+
tion|sync-tag-invalidate>
|
|
414
429
|
--javascript Use JavaScript instead of TypeScript
|
|
415
430
|
--json Format output as json
|
|
416
431
|
--language=<option> [default: ts] Language of the new function
|
|
@@ -503,7 +518,9 @@ DESCRIPTION
|
|
|
503
518
|
|
|
504
519
|
Use --fn-installer to force which package manager to use when deploying functions.
|
|
505
520
|
|
|
506
|
-
Set SANITY_ASSET_TIMEOUT (seconds) to override the
|
|
521
|
+
Set SANITY_ASSET_TIMEOUT (seconds) to override the 180-second timeout for processing resource assets.
|
|
522
|
+
|
|
523
|
+
Set SANITY_ASSET_CONCURRENCY to override how many resource assets are processed at once (default 4).
|
|
507
524
|
|
|
508
525
|
Exit codes: 0 deployed, 2 deployment failed, 75 deployment accepted but completion could not be confirmed (rerun
|
|
509
526
|
'blueprints info' to check).
|
|
@@ -530,16 +547,16 @@ Destroy a remote Stack deployment and its resources
|
|
|
530
547
|
|
|
531
548
|
```
|
|
532
549
|
USAGE
|
|
533
|
-
$ sanity blueprints destroy [--json] [--project-id <value> --stack <value>
|
|
550
|
+
$ sanity blueprints destroy [--json] [--project-id <value> --stack <value> -f] [--organization-id <value> ]
|
|
534
551
|
[--no-wait]
|
|
535
552
|
|
|
536
553
|
FLAGS
|
|
537
|
-
--force Force Stack destruction (skip confirmation)
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
554
|
+
-f, --force Force Stack destruction (skip confirmation)
|
|
555
|
+
--json Format output as json
|
|
556
|
+
--no-wait Do not wait for Stack destruction to complete
|
|
557
|
+
--organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
|
|
558
|
+
--project-id=<value> Sanity project ID used to scope Blueprint and Stack
|
|
559
|
+
--stack=<value> Stack name or ID to destroy (defaults to the locally configured Stack)
|
|
543
560
|
|
|
544
561
|
DESCRIPTION
|
|
545
562
|
Destroy a remote Stack deployment and its resources
|
|
@@ -596,13 +613,14 @@ Display the status and resources of the remote Stack deployment
|
|
|
596
613
|
|
|
597
614
|
```
|
|
598
615
|
USAGE
|
|
599
|
-
$ sanity blueprints info [--json] [--stack <value>] [--project-id <value> | --organization-id <value>]
|
|
616
|
+
$ sanity blueprints info [--json] [-v] [--stack <value>] [--project-id <value> | --organization-id <value>]
|
|
600
617
|
|
|
601
618
|
FLAGS
|
|
602
|
-
--
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
619
|
+
-v, --verbose Show resource and external IDs
|
|
620
|
+
--json Format output as json
|
|
621
|
+
--organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
|
|
622
|
+
--project-id=<value> Sanity project ID used to scope Blueprint and Stack
|
|
623
|
+
--stack=<value> Stack name or ID
|
|
606
624
|
|
|
607
625
|
DESCRIPTION
|
|
608
626
|
Display the status and resources of the remote Stack deployment
|
|
@@ -653,12 +671,12 @@ DESCRIPTION
|
|
|
653
671
|
|
|
654
672
|
A Blueprint is your local infrastructure-as-code configuration that defines Sanity resources (datasets, functions,
|
|
655
673
|
etc.). A Stack is the remote deployment target where your Blueprint is applied.
|
|
656
|
-
[NOTE: Currently, accounts are limited to three (3) Stacks per project scope.]
|
|
657
674
|
|
|
658
675
|
This is typically the first command you run in a new project. It creates a local Blueprint manifest file
|
|
659
676
|
(sanity.blueprint.ts, .js, or .json) and provisions a new remote Stack.
|
|
660
|
-
Additionally, a Blueprint configuration file is created in .sanity/ containing the scope and Stack IDs.
|
|
661
|
-
.
|
|
677
|
+
Additionally, a Blueprint configuration file is created in .sanity/ containing the scope and Stack IDs. A .gitignore
|
|
678
|
+
covering node_modules, .env, and Function build output is created or updated; the .sanity/ config itself is not
|
|
679
|
+
ignored.
|
|
662
680
|
|
|
663
681
|
After initialization, use 'blueprints plan' to preview changes, then 'blueprints deploy' to apply them.
|
|
664
682
|
|
|
@@ -693,8 +711,8 @@ Display logs for the current Blueprint's Stack deployment
|
|
|
693
711
|
|
|
694
712
|
```
|
|
695
713
|
USAGE
|
|
696
|
-
$ sanity blueprints logs [--
|
|
697
|
-
|
|
714
|
+
$ sanity blueprints logs [--stack <value>] [--project-id <value> | --organization-id <value>] [-l <value> | [-w |
|
|
715
|
+
--json]] [--since <value> | ] [--before <value> | ]
|
|
698
716
|
|
|
699
717
|
FLAGS
|
|
700
718
|
-l, --limit=<value> Maximum number of log entries to retrieve (1-500)
|
|
@@ -844,9 +862,10 @@ List remote Stack deployments for your project or organization
|
|
|
844
862
|
|
|
845
863
|
```
|
|
846
864
|
USAGE
|
|
847
|
-
$ sanity blueprints stacks [--json] [--project-id <value> | --organization-id <value> | --include-projects]
|
|
865
|
+
$ sanity blueprints stacks [--json] [--project-id <value> | --organization-id <value> | --include-projects | --all]
|
|
848
866
|
|
|
849
867
|
FLAGS
|
|
868
|
+
--all List Stacks from every organization and project you have access to
|
|
850
869
|
--include-projects Include Stacks from all projects within the organization. Requires --organization-id.
|
|
851
870
|
--json Format output as json
|
|
852
871
|
--organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
|
|
@@ -860,11 +879,14 @@ DESCRIPTION
|
|
|
860
879
|
Use this to discover existing Stacks you can scope a local Blueprint to (using 'blueprints config --edit'), or to
|
|
861
880
|
audit what's deployed across your project.
|
|
862
881
|
|
|
863
|
-
|
|
882
|
+
Without a scope, prompts for an organization or project. Use --all to list Stacks across every organization and
|
|
883
|
+
project you can access, or --include-projects with --organization-id for one organization and its projects.
|
|
864
884
|
|
|
865
885
|
EXAMPLES
|
|
866
886
|
$ sanity blueprints stacks
|
|
867
887
|
|
|
888
|
+
$ sanity blueprints stacks --all
|
|
889
|
+
|
|
868
890
|
$ sanity blueprints stacks --project-id <projectId>
|
|
869
891
|
|
|
870
892
|
$ sanity blueprints stacks --organization-id <organizationId>
|
|
@@ -2027,13 +2049,13 @@ Add a Function to your Blueprint
|
|
|
2027
2049
|
|
|
2028
2050
|
```
|
|
2029
2051
|
USAGE
|
|
2030
|
-
$ sanity functions add [--json] [--example <value> | -n <value> |
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
skip|npm|pnpm|yarn
|
|
2052
|
+
$ sanity functions add [--json] [--example <value> | -n <value> | --type
|
|
2053
|
+
document-publish|document-create|document-delete|document-update|media-library-asset-create|media-library-asset-dele
|
|
2054
|
+
te|media-library-asset-update|pub-sub|scheduled-function|sync-tag-invalidate... | --language ts|js | --javascript |
|
|
2055
|
+
--helpers | --installer skip|npm|pnpm|yarn | -i]
|
|
2034
2056
|
|
|
2035
2057
|
FLAGS
|
|
2036
|
-
-i, --install Shortcut for --
|
|
2058
|
+
-i, --install Shortcut for --installer npm
|
|
2037
2059
|
-n, --name=<value> Name of the Function to add
|
|
2038
2060
|
--example=<value> Example to use for the Function
|
|
2039
2061
|
--[no-]helpers Add helpers to the new Function
|
|
@@ -2046,8 +2068,8 @@ FLAGS
|
|
|
2046
2068
|
--type=<option>... Document change event(s) that should trigger the function; you can specify multiple events
|
|
2047
2069
|
by specifying this flag multiple times
|
|
2048
2070
|
<options: document-publish|document-create|document-delete|document-update|media-library-ass
|
|
2049
|
-
et-create|media-library-asset-delete|media-library-asset-update|scheduled-function|
|
|
2050
|
-
invalidate>
|
|
2071
|
+
et-create|media-library-asset-delete|media-library-asset-update|pub-sub|scheduled-function|s
|
|
2072
|
+
ync-tag-invalidate>
|
|
2051
2073
|
|
|
2052
2074
|
DESCRIPTION
|
|
2053
2075
|
Add a Function to your Blueprint
|
|
@@ -2093,13 +2115,13 @@ DESCRIPTION
|
|
|
2093
2115
|
|
|
2094
2116
|
Open the emulator in your browser to interactively test your functions with the payload editor.
|
|
2095
2117
|
|
|
2096
|
-
Optionally, set the host and port with the --host and --port flags.
|
|
2097
|
-
--timeout flag.
|
|
2118
|
+
Optionally, set the host and port with the --host and --port flags. Port 8974 is reserved for the emulator's
|
|
2119
|
+
live-reload WebSocket server. Function timeout can be configured with the --timeout flag.
|
|
2098
2120
|
|
|
2099
2121
|
To invoke a function with the CLI, use 'functions test'.
|
|
2100
2122
|
|
|
2101
2123
|
EXAMPLES
|
|
2102
|
-
$ sanity functions dev --host 127.0.0.1 --port
|
|
2124
|
+
$ sanity functions dev --host 127.0.0.1 --port 3333
|
|
2103
2125
|
|
|
2104
2126
|
$ sanity functions dev --timeout 60
|
|
2105
2127
|
```
|
|
@@ -2199,7 +2221,7 @@ Retrieve or delete logs for a Sanity Function
|
|
|
2199
2221
|
|
|
2200
2222
|
```
|
|
2201
2223
|
USAGE
|
|
2202
|
-
$ sanity functions logs [NAME] [--stack <value>] [-u] [-f [-d | -l <value> | --json]] [-w]
|
|
2224
|
+
$ sanity functions logs [NAME] [--stack <value>] [-u] [-f [-d | -l <value> | --json]] [-w | ]
|
|
2203
2225
|
|
|
2204
2226
|
ARGUMENTS
|
|
2205
2227
|
[NAME] The name of the Sanity Function
|
|
@@ -2240,7 +2262,7 @@ USAGE
|
|
|
2240
2262
|
$ sanity functions test [NAME] [--json] [--data-before <value> | [-d <value> | -f <value> | --document-id <value>]
|
|
2241
2263
|
| | | --file-before <value> | --file-after <value> | --document-id-before <value> | --document-id-after <value>]
|
|
2242
2264
|
[--data-after <value> | | | | | | | ] [-e create|update|delete] [-t <value>] [-a <value>] [--with-user-token]
|
|
2243
|
-
[--media-library-id <value> | [--project-id <value> | --organization-id <value>] | --dataset <value>]
|
|
2265
|
+
[--media-library-id <value> | [--project-id <value> | --organization-id <value>] | --dataset <value>] [--no-wait]
|
|
2244
2266
|
|
|
2245
2267
|
ARGUMENTS
|
|
2246
2268
|
[NAME] The name of the Sanity Function
|
|
@@ -2262,6 +2284,7 @@ FLAGS
|
|
|
2262
2284
|
--file-before=<value> Original document
|
|
2263
2285
|
--json Format output as json
|
|
2264
2286
|
--media-library-id=<value> Sanity Media Library ID to use
|
|
2287
|
+
--no-wait Skip durable wait delays instead of sleeping
|
|
2265
2288
|
--organization-id=<value> Sanity organization ID used to scope Blueprint and Stack
|
|
2266
2289
|
--project-id=<value> Sanity project ID used to scope Blueprint and Stack
|
|
2267
2290
|
--with-user-token Prime access token from CLI config
|
|
@@ -2793,14 +2816,14 @@ Delete an aspect definition
|
|
|
2793
2816
|
|
|
2794
2817
|
```
|
|
2795
2818
|
USAGE
|
|
2796
|
-
$ sanity media delete-aspect ASPECTNAME [-p <id>] [--media-library-id <value>] [
|
|
2819
|
+
$ sanity media delete-aspect ASPECTNAME [-p <id>] [--media-library-id <value>] [-y]
|
|
2797
2820
|
|
|
2798
2821
|
ARGUMENTS
|
|
2799
2822
|
ASPECTNAME Name of the aspect to delete
|
|
2800
2823
|
|
|
2801
2824
|
FLAGS
|
|
2802
|
-
|
|
2803
|
-
|
|
2825
|
+
-y, --yes Run without prompts and confirm deletion
|
|
2826
|
+
--media-library-id=<value> The id of the target media library
|
|
2804
2827
|
|
|
2805
2828
|
OVERRIDE FLAGS
|
|
2806
2829
|
-p, --project-id=<id> Project ID to delete media aspect from (overrides CLI configuration)
|
|
@@ -3686,13 +3709,13 @@ Delete an API token from the project
|
|
|
3686
3709
|
|
|
3687
3710
|
```
|
|
3688
3711
|
USAGE
|
|
3689
|
-
$ sanity tokens delete [TOKENID] [-p <id>] [
|
|
3712
|
+
$ sanity tokens delete [TOKENID] [-p <id>] [-y]
|
|
3690
3713
|
|
|
3691
3714
|
ARGUMENTS
|
|
3692
3715
|
[TOKENID] Token ID to delete (will prompt if not provided)
|
|
3693
3716
|
|
|
3694
3717
|
FLAGS
|
|
3695
|
-
--yes Skip confirmation prompt (unattended mode)
|
|
3718
|
+
-y, --yes Skip confirmation prompt (unattended mode)
|
|
3696
3719
|
|
|
3697
3720
|
OVERRIDE FLAGS
|
|
3698
3721
|
-p, --project-id=<id> Project ID to delete token from (overrides CLI configuration)
|
|
@@ -3945,4 +3968,463 @@ EXAMPLES
|
|
|
3945
3968
|
$ sanity versions
|
|
3946
3969
|
```
|
|
3947
3970
|
|
|
3971
|
+
## `sanity workflows abort INSTANCEID`
|
|
3972
|
+
|
|
3973
|
+
Abort an in-flight workflow instance — a hard stop: pending effects are cancelled, stage guards removed, and the instance is marked terminal where it stands.
|
|
3974
|
+
|
|
3975
|
+
```
|
|
3976
|
+
USAGE
|
|
3977
|
+
$ sanity workflows abort INSTANCEID [--deployment <value> | --tag <value>] [--reason <value>]
|
|
3978
|
+
|
|
3979
|
+
ARGUMENTS
|
|
3980
|
+
INSTANCEID Workflow instance id.
|
|
3981
|
+
|
|
3982
|
+
FLAGS
|
|
3983
|
+
--deployment=<value> Deployment name — narrow the instance search to the resource that deployment targets; the tag
|
|
3984
|
+
partition still comes from the loaded instance.
|
|
3985
|
+
--reason=<value> Reason for aborting (recorded in history).
|
|
3986
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
3987
|
+
resources are searched; omit to span them all.
|
|
3988
|
+
|
|
3989
|
+
DESCRIPTION
|
|
3990
|
+
Abort an in-flight workflow instance — a hard stop: pending effects are cancelled, stage guards removed, and the
|
|
3991
|
+
instance is marked terminal where it stands.
|
|
3992
|
+
|
|
3993
|
+
EXAMPLES
|
|
3994
|
+
$ sanity workflows abort wf-instance.abc123
|
|
3995
|
+
|
|
3996
|
+
$ sanity workflows abort wf-instance.abc123 --reason 'superseded by relaunch'
|
|
3997
|
+
```
|
|
3998
|
+
|
|
3999
|
+
## `sanity workflows definition delete NAME`
|
|
4000
|
+
|
|
4001
|
+
Delete a deployed workflow definition (every version, or one via --version). Refuses while non-terminal instances exist unless --cascade aborts them first — instances are aborted in place, never deleted.
|
|
4002
|
+
|
|
4003
|
+
```
|
|
4004
|
+
USAGE
|
|
4005
|
+
$ sanity workflows definition delete NAME [--deployment <value> | --tag <value>] [--version <value>] [--cascade] [--reason
|
|
4006
|
+
<value>]
|
|
4007
|
+
|
|
4008
|
+
ARGUMENTS
|
|
4009
|
+
NAME Workflow definition name.
|
|
4010
|
+
|
|
4011
|
+
FLAGS
|
|
4012
|
+
--cascade Abort every non-terminal instance pinned to the targeted versions, then delete.
|
|
4013
|
+
--deployment=<value> Deployment name — the unique identity of one deployment in the config.
|
|
4014
|
+
--reason=<value> Free-text reason — recorded on each cascade-abort history entry.
|
|
4015
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — selects the deployment to act on while the tag
|
|
4016
|
+
names exactly one; pass --deployment when it spans several.
|
|
4017
|
+
--version=<value> Delete only this deployed version (default: every version).
|
|
4018
|
+
|
|
4019
|
+
DESCRIPTION
|
|
4020
|
+
Delete a deployed workflow definition (every version, or one via --version). Refuses while non-terminal instances
|
|
4021
|
+
exist unless --cascade aborts them first — instances are aborted in place, never deleted.
|
|
4022
|
+
|
|
4023
|
+
EXAMPLES
|
|
4024
|
+
$ sanity workflows definition delete my-workflow
|
|
4025
|
+
|
|
4026
|
+
$ sanity workflows definition delete my-workflow --version 2
|
|
4027
|
+
|
|
4028
|
+
$ sanity workflows definition delete my-workflow --cascade --reason 'workflow retired'
|
|
4029
|
+
```
|
|
4030
|
+
|
|
4031
|
+
## `sanity workflows definition diff NAME`
|
|
4032
|
+
|
|
4033
|
+
Diff an in-code definition against the deployed version (latest by default).
|
|
4034
|
+
|
|
4035
|
+
```
|
|
4036
|
+
USAGE
|
|
4037
|
+
$ sanity workflows definition diff NAME [--deployment <value> | --tag <value>] [--version <value>]
|
|
4038
|
+
|
|
4039
|
+
ARGUMENTS
|
|
4040
|
+
NAME Workflow definition name.
|
|
4041
|
+
|
|
4042
|
+
FLAGS
|
|
4043
|
+
--deployment=<value> Deployment name — the unique identity of one deployment in the config.
|
|
4044
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — selects the deployment to act on while the tag
|
|
4045
|
+
names exactly one; pass --deployment when it spans several.
|
|
4046
|
+
--version=<value> Deployed version to diff against (default: latest).
|
|
4047
|
+
|
|
4048
|
+
DESCRIPTION
|
|
4049
|
+
Diff an in-code definition against the deployed version (latest by default).
|
|
4050
|
+
|
|
4051
|
+
EXAMPLES
|
|
4052
|
+
$ sanity workflows definition diff productLaunch
|
|
4053
|
+
|
|
4054
|
+
$ sanity workflows definition diff productLaunch --version 2
|
|
4055
|
+
```
|
|
4056
|
+
|
|
4057
|
+
## `sanity workflows definition list`
|
|
4058
|
+
|
|
4059
|
+
List deployed workflow definitions.
|
|
4060
|
+
|
|
4061
|
+
```
|
|
4062
|
+
USAGE
|
|
4063
|
+
$ sanity workflows definition list [--tag <value>] [--limit <value>] [--name <value>] [--json]
|
|
4064
|
+
|
|
4065
|
+
FLAGS
|
|
4066
|
+
--json Emit structured JSON instead of rendered output.
|
|
4067
|
+
--limit=<value> [default: 100] The maximum number of definitions to return.
|
|
4068
|
+
--name=<value> Filter to a single workflow definition name (e.g. product-launch).
|
|
4069
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
4070
|
+
resources are searched; omit to span them all.
|
|
4071
|
+
|
|
4072
|
+
DESCRIPTION
|
|
4073
|
+
List deployed workflow definitions.
|
|
4074
|
+
|
|
4075
|
+
EXAMPLES
|
|
4076
|
+
$ sanity workflows definition list
|
|
4077
|
+
|
|
4078
|
+
$ sanity workflows definition list --tag prod
|
|
4079
|
+
|
|
4080
|
+
$ sanity workflows definition list --json
|
|
4081
|
+
```
|
|
4082
|
+
|
|
4083
|
+
## `sanity workflows definition show NAME`
|
|
4084
|
+
|
|
4085
|
+
Show a deployed workflow definition.
|
|
4086
|
+
|
|
4087
|
+
```
|
|
4088
|
+
USAGE
|
|
4089
|
+
$ sanity workflows definition show NAME [--tag <value>] [--version <value>] [--json]
|
|
4090
|
+
|
|
4091
|
+
ARGUMENTS
|
|
4092
|
+
NAME Workflow definition name.
|
|
4093
|
+
|
|
4094
|
+
FLAGS
|
|
4095
|
+
--json Emit structured JSON instead of rendered output.
|
|
4096
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
4097
|
+
resources are searched; omit to span them all.
|
|
4098
|
+
--version=<value> Specific version (default: latest).
|
|
4099
|
+
|
|
4100
|
+
DESCRIPTION
|
|
4101
|
+
Show a deployed workflow definition.
|
|
4102
|
+
```
|
|
4103
|
+
|
|
4104
|
+
## `sanity workflows deploy`
|
|
4105
|
+
|
|
4106
|
+
Validate, diff, and deploy workflow definitions to the resource bound by the selected deployment.
|
|
4107
|
+
|
|
4108
|
+
```
|
|
4109
|
+
USAGE
|
|
4110
|
+
$ sanity workflows deploy [--all-tags | | [--deployment <value> | --tag <value>]] [--dry-run] [--check] [--only
|
|
4111
|
+
<value>] [--share-defs]
|
|
4112
|
+
|
|
4113
|
+
FLAGS
|
|
4114
|
+
--all-tags Deploy every deployment in the config, not just a selection.
|
|
4115
|
+
--check Validate definitions only; do not contact the dataset.
|
|
4116
|
+
--deployment=<value> Deployment name — the unique identity of one deployment in the config.
|
|
4117
|
+
--dry-run Validate + diff against the deployed version; do not write.
|
|
4118
|
+
--only=<value> Limit deploy/check/diff to a single workflow definition by name (deployments are selected with
|
|
4119
|
+
--deployment). Every targeted deployment must contain it.
|
|
4120
|
+
--[no-]share-defs Share the definition documents newly created by this deploy with Sanity — the full document,
|
|
4121
|
+
verbatim (structure, names, filters, effect configuration, seeded values), plus its deployment
|
|
4122
|
+
coordinates (project and dataset, or resource id); never content documents, instances, or your
|
|
4123
|
+
Sanity auth token. Sharing is the default in every environment, including CI / non-TTY /
|
|
4124
|
+
DO_NOT_TRACK. Use --no-share-defs to opt out.
|
|
4125
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — deploys every deployment carrying the tag (a tag is
|
|
4126
|
+
an environment group).
|
|
4127
|
+
|
|
4128
|
+
DESCRIPTION
|
|
4129
|
+
Validate, diff, and deploy workflow definitions to the resource bound by the selected deployment.
|
|
4130
|
+
|
|
4131
|
+
EXAMPLES
|
|
4132
|
+
$ sanity workflows deploy --deployment review-prod
|
|
4133
|
+
|
|
4134
|
+
$ sanity workflows deploy --tag prod
|
|
4135
|
+
|
|
4136
|
+
$ sanity workflows deploy --all-tags
|
|
4137
|
+
|
|
4138
|
+
$ sanity workflows deploy --check
|
|
4139
|
+
|
|
4140
|
+
$ sanity workflows deploy --dry-run
|
|
4141
|
+
|
|
4142
|
+
$ sanity workflows deploy --only productLaunch
|
|
4143
|
+
```
|
|
4144
|
+
|
|
4145
|
+
## `sanity workflows diagnose INSTANCEID`
|
|
4146
|
+
|
|
4147
|
+
Explain why a workflow instance is or isn't progressing, and what would unstick it.
|
|
4148
|
+
|
|
4149
|
+
```
|
|
4150
|
+
USAGE
|
|
4151
|
+
$ sanity workflows diagnose INSTANCEID [--deployment <value> | --tag <value>] [--json]
|
|
4152
|
+
|
|
4153
|
+
ARGUMENTS
|
|
4154
|
+
INSTANCEID Workflow instance id.
|
|
4155
|
+
|
|
4156
|
+
FLAGS
|
|
4157
|
+
--deployment=<value> Deployment name — narrow the instance search to the resource that deployment targets; the tag
|
|
4158
|
+
partition still comes from the loaded instance.
|
|
4159
|
+
--json Emit structured JSON instead of rendered output.
|
|
4160
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
4161
|
+
resources are searched; omit to span them all.
|
|
4162
|
+
|
|
4163
|
+
DESCRIPTION
|
|
4164
|
+
Explain why a workflow instance is or isn't progressing, and what would unstick it.
|
|
4165
|
+
|
|
4166
|
+
EXAMPLES
|
|
4167
|
+
$ sanity workflows diagnose wf-instance.abc123
|
|
4168
|
+
|
|
4169
|
+
$ sanity workflows diagnose wf-instance.abc123 --tag prod
|
|
4170
|
+
|
|
4171
|
+
$ sanity workflows diagnose wf-instance.abc123 --json
|
|
4172
|
+
```
|
|
4173
|
+
|
|
4174
|
+
## `sanity workflows fire-action INSTANCEID`
|
|
4175
|
+
|
|
4176
|
+
Fire an action on an instance to unstick a waiting activity — the write acts as the configured token. Omit --action to list what can be fired.
|
|
4177
|
+
|
|
4178
|
+
```
|
|
4179
|
+
USAGE
|
|
4180
|
+
$ sanity workflows fire-action INSTANCEID [--deployment <value> | --tag <value>] [--activity <value>] [--action <value>]
|
|
4181
|
+
[--param <value>...] [--json]
|
|
4182
|
+
|
|
4183
|
+
ARGUMENTS
|
|
4184
|
+
INSTANCEID Workflow instance id.
|
|
4185
|
+
|
|
4186
|
+
FLAGS
|
|
4187
|
+
--action=<value> Action to fire. Omit to list the actions available on the instance.
|
|
4188
|
+
--activity=<value> Activity the action belongs to. Required to fire; omit --action to list.
|
|
4189
|
+
--deployment=<value> Deployment name — narrow the instance search to the resource that deployment targets; the tag
|
|
4190
|
+
partition still comes from the loaded instance.
|
|
4191
|
+
--json Emit structured JSON instead of rendered output.
|
|
4192
|
+
--param=<value>... [default: ] Action param as key=value (repeatable). Values are JSON-parsed, falling back to a
|
|
4193
|
+
string.
|
|
4194
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
4195
|
+
resources are searched; omit to span them all.
|
|
4196
|
+
|
|
4197
|
+
DESCRIPTION
|
|
4198
|
+
Fire an action on an instance to unstick a waiting activity — the write acts as the configured token. Omit --action to
|
|
4199
|
+
list what can be fired.
|
|
4200
|
+
|
|
4201
|
+
EXAMPLES
|
|
4202
|
+
$ sanity workflows fire-action wf-instance.abc123
|
|
4203
|
+
|
|
4204
|
+
$ sanity workflows fire-action wf-instance.abc123 --activity approve --action approve
|
|
4205
|
+
|
|
4206
|
+
$ sanity workflows fire-action wf-instance.abc123 --activity publish --action publish --param note=shipping
|
|
4207
|
+
```
|
|
4208
|
+
|
|
4209
|
+
## `sanity workflows list`
|
|
4210
|
+
|
|
4211
|
+
List workflow instances in the configured dataset (in-flight by default).
|
|
4212
|
+
|
|
4213
|
+
```
|
|
4214
|
+
USAGE
|
|
4215
|
+
$ sanity workflows list [--tag <value>] [--include-completed] [--failed] [--definition <value>] [--document
|
|
4216
|
+
<value>] [--limit <value>] [--json]
|
|
4217
|
+
|
|
4218
|
+
FLAGS
|
|
4219
|
+
--definition=<value> Only instances of this workflow definition (its `name`; the instance's `definition` field).
|
|
4220
|
+
--document=<value> Only instances that reference this document (resource-qualified GDR URI, e.g.
|
|
4221
|
+
"dataset:proj:ds:article-1").
|
|
4222
|
+
--failed Only instances with at least one failed activity.
|
|
4223
|
+
--include-completed Include completed/aborted instances (default: in-flight only).
|
|
4224
|
+
--json Emit structured JSON instead of rendered output.
|
|
4225
|
+
--limit=<value> [default: 50] Maximum rows to return.
|
|
4226
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
4227
|
+
resources are searched; omit to span them all.
|
|
4228
|
+
|
|
4229
|
+
DESCRIPTION
|
|
4230
|
+
List workflow instances in the configured dataset (in-flight by default).
|
|
4231
|
+
|
|
4232
|
+
EXAMPLES
|
|
4233
|
+
$ sanity workflows list
|
|
4234
|
+
|
|
4235
|
+
$ sanity workflows list --include-completed
|
|
4236
|
+
|
|
4237
|
+
$ sanity workflows list --definition productLaunch
|
|
4238
|
+
|
|
4239
|
+
$ sanity workflows list --document dataset:proj:ds:article-1
|
|
4240
|
+
|
|
4241
|
+
$ sanity workflows list --tag prod
|
|
4242
|
+
|
|
4243
|
+
$ sanity workflows list --json
|
|
4244
|
+
```
|
|
4245
|
+
|
|
4246
|
+
## `sanity workflows nuke`
|
|
4247
|
+
|
|
4248
|
+
Delete engine-owned documents — a whole deployment tag, or a single instance.
|
|
4249
|
+
|
|
4250
|
+
```
|
|
4251
|
+
USAGE
|
|
4252
|
+
$ sanity workflows nuke [--deployment <value>] [--tag <value>] [--instance <value>] [--force]
|
|
4253
|
+
|
|
4254
|
+
FLAGS
|
|
4255
|
+
--deployment=<value> The deployment name to reset. With --instance, narrows which deployment the instance is looked
|
|
4256
|
+
up in when its tag spans several.
|
|
4257
|
+
--force Skip the confirmation prompt (for scripts/CI). The plan still prints.
|
|
4258
|
+
--instance=<value> Delete a single terminal instance by id, plus its guard docs, instead of a tag.
|
|
4259
|
+
--tag=<value> The deployment tag to reset (while it names exactly one deployment). Not valid with --instance,
|
|
4260
|
+
which reads its tag from the instance id.
|
|
4261
|
+
|
|
4262
|
+
DESCRIPTION
|
|
4263
|
+
Delete engine-owned documents — a whole deployment tag, or a single instance.
|
|
4264
|
+
|
|
4265
|
+
The reset for a dataset holding engine documents the versioned upgrade framework cannot yet migrate: deletes the tag's
|
|
4266
|
+
instances, definitions, and guards (across every alias-bound resource). --instance <id> instead deletes one terminal
|
|
4267
|
+
instance plus its guards. Content documents are never touched. Prints a dry-run plan, then confirms (--force skips the
|
|
4268
|
+
prompt; the plan still prints).
|
|
4269
|
+
|
|
4270
|
+
EXAMPLES
|
|
4271
|
+
$ sanity workflows nuke --deployment plugin-dev
|
|
4272
|
+
|
|
4273
|
+
$ sanity workflows nuke --tag plugin-dev --force
|
|
4274
|
+
|
|
4275
|
+
$ sanity workflows nuke --instance plugin-dev.wf-instance.abc123
|
|
4276
|
+
```
|
|
4277
|
+
|
|
4278
|
+
## `sanity workflows reset-activity INSTANCEID ACTIVITY`
|
|
4279
|
+
|
|
4280
|
+
Reset a failed activity on an in-flight instance — back to active to re-run it, or --skip to bypass it (mark it skipped) so a gated exit transition can fire.
|
|
4281
|
+
|
|
4282
|
+
```
|
|
4283
|
+
USAGE
|
|
4284
|
+
$ sanity workflows reset-activity INSTANCEID ACTIVITY [--deployment <value> | --tag <value>] [--skip]
|
|
4285
|
+
|
|
4286
|
+
ARGUMENTS
|
|
4287
|
+
INSTANCEID Workflow instance id.
|
|
4288
|
+
ACTIVITY Activity name within the current stage.
|
|
4289
|
+
|
|
4290
|
+
FLAGS
|
|
4291
|
+
--deployment=<value> Deployment name — narrow the instance search to the resource that deployment targets; the tag
|
|
4292
|
+
partition still comes from the loaded instance.
|
|
4293
|
+
--skip Bypass the activity (mark it skipped) instead of re-running it (back to active).
|
|
4294
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
4295
|
+
resources are searched; omit to span them all.
|
|
4296
|
+
|
|
4297
|
+
DESCRIPTION
|
|
4298
|
+
Reset a failed activity on an in-flight instance — back to active to re-run it, or --skip to bypass it (mark it
|
|
4299
|
+
skipped) so a gated exit transition can fire.
|
|
4300
|
+
|
|
4301
|
+
EXAMPLES
|
|
4302
|
+
$ sanity workflows reset-activity wf-instance.abc123 legal-review
|
|
4303
|
+
|
|
4304
|
+
$ sanity workflows reset-activity wf-instance.abc123 legal-review --skip
|
|
4305
|
+
```
|
|
4306
|
+
|
|
4307
|
+
## `sanity workflows set-stage INSTANCEID`
|
|
4308
|
+
|
|
4309
|
+
Force an instance into a stage, regardless of its declared transitions and filters — the engine's setStage admin override. The target stage's enter lifecycle still runs (auto-activities start, stage guards reconcile), and the post-move cascade can immediately auto-transition the instance onward.
|
|
4310
|
+
|
|
4311
|
+
```
|
|
4312
|
+
USAGE
|
|
4313
|
+
$ sanity workflows set-stage INSTANCEID [--deployment <value> | --tag <value>] [--to <value>] [--reason <value>]
|
|
4314
|
+
|
|
4315
|
+
ARGUMENTS
|
|
4316
|
+
INSTANCEID Workflow instance id to move.
|
|
4317
|
+
|
|
4318
|
+
FLAGS
|
|
4319
|
+
--deployment=<value> Deployment name — narrow the instance search to the resource that deployment targets; the tag
|
|
4320
|
+
partition still comes from the loaded instance.
|
|
4321
|
+
--reason=<value> Free-text reason — recorded on the history entry for audit.
|
|
4322
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
4323
|
+
resources are searched; omit to span them all.
|
|
4324
|
+
--to=<value> Target stage name. Omit on an interactive terminal to pick from the workflow’s stages.
|
|
4325
|
+
|
|
4326
|
+
DESCRIPTION
|
|
4327
|
+
Force an instance into a stage, regardless of its declared transitions and filters — the engine's setStage admin
|
|
4328
|
+
override. The target stage's enter lifecycle still runs (auto-activities start, stage guards reconcile), and the
|
|
4329
|
+
post-move cascade can immediately auto-transition the instance onward.
|
|
4330
|
+
|
|
4331
|
+
EXAMPLES
|
|
4332
|
+
$ sanity workflows set-stage wf-instance.abc123 --to ready
|
|
4333
|
+
|
|
4334
|
+
$ sanity workflows set-stage wf-instance.abc123
|
|
4335
|
+
|
|
4336
|
+
$ sanity workflows set-stage wf-instance.abc123 --to ready --reason 'unblock for demo'
|
|
4337
|
+
```
|
|
4338
|
+
|
|
4339
|
+
## `sanity workflows show INSTANCEID`
|
|
4340
|
+
|
|
4341
|
+
Show the state, activities, and effects of a workflow instance.
|
|
4342
|
+
|
|
4343
|
+
```
|
|
4344
|
+
USAGE
|
|
4345
|
+
$ sanity workflows show INSTANCEID [--tag <value>] [--include history...] [--json]
|
|
4346
|
+
|
|
4347
|
+
ARGUMENTS
|
|
4348
|
+
INSTANCEID Workflow instance document id.
|
|
4349
|
+
|
|
4350
|
+
FLAGS
|
|
4351
|
+
--include=<option>... [default: ] Optional sections to include in rendered output (--json always carries the full
|
|
4352
|
+
document).
|
|
4353
|
+
<options: history>
|
|
4354
|
+
--json Emit structured JSON instead of rendered output.
|
|
4355
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which
|
|
4356
|
+
resources are searched; omit to span them all.
|
|
4357
|
+
|
|
4358
|
+
DESCRIPTION
|
|
4359
|
+
Show the state, activities, and effects of a workflow instance.
|
|
4360
|
+
|
|
4361
|
+
EXAMPLES
|
|
4362
|
+
$ sanity workflows show wf-instance.abc123
|
|
4363
|
+
|
|
4364
|
+
$ sanity workflows show wf-instance.abc123 --include history
|
|
4365
|
+
|
|
4366
|
+
$ sanity workflows show wf-instance.abc123 --json
|
|
4367
|
+
```
|
|
4368
|
+
|
|
4369
|
+
## `sanity workflows start NAME`
|
|
4370
|
+
|
|
4371
|
+
Start a workflow instance from a deployed definition. Supply values for the workflow's input-sourced fields with --field (e.g. the subject document ref).
|
|
4372
|
+
|
|
4373
|
+
```
|
|
4374
|
+
USAGE
|
|
4375
|
+
$ sanity workflows start NAME [--deployment <value> | --tag <value>] [--version <value>] [--field <value>...]
|
|
4376
|
+
[--instance-id <value>] [--json]
|
|
4377
|
+
|
|
4378
|
+
ARGUMENTS
|
|
4379
|
+
NAME Workflow definition name.
|
|
4380
|
+
|
|
4381
|
+
FLAGS
|
|
4382
|
+
--deployment=<value> Deployment name — the unique identity of one deployment in the config.
|
|
4383
|
+
--field=<value>... [default: ] Initial value for a declared input-sourced field, as name=value (repeatable).
|
|
4384
|
+
Values are JSON-parsed, falling back to a string; ref kinds take a JSON object with a GDR `id`
|
|
4385
|
+
and doc `type`.
|
|
4386
|
+
--instance-id=<value> Start under this instance id — for retries. The id is the start's idempotency key: pass the id
|
|
4387
|
+
of a start that failed partway and the engine resumes it instead of creating a duplicate (an
|
|
4388
|
+
already-settled start replays as a no-op). Omit to mint a fresh id.
|
|
4389
|
+
--json Emit structured JSON instead of rendered output.
|
|
4390
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — selects the deployment to act on while the tag
|
|
4391
|
+
names exactly one; pass --deployment when it spans several.
|
|
4392
|
+
--version=<value> Definition version to start from (default: highest deployed).
|
|
4393
|
+
|
|
4394
|
+
DESCRIPTION
|
|
4395
|
+
Start a workflow instance from a deployed definition. Supply values for the workflow's input-sourced fields with
|
|
4396
|
+
--field (e.g. the subject document ref).
|
|
4397
|
+
|
|
4398
|
+
EXAMPLES
|
|
4399
|
+
$ sanity workflows start productLaunch
|
|
4400
|
+
|
|
4401
|
+
$ sanity workflows start article-review --field subject='{"id":"dataset:proj:ds:article-1","type":"article"}'
|
|
4402
|
+
|
|
4403
|
+
$ sanity workflows start productLaunch --version 2 --tag prod
|
|
4404
|
+
|
|
4405
|
+
$ sanity workflows start productLaunch --instance-id prod.wf-instance.a1b2c3d4e5f6
|
|
4406
|
+
```
|
|
4407
|
+
|
|
4408
|
+
## `sanity workflows tail INSTANCEID`
|
|
4409
|
+
|
|
4410
|
+
Stream new history entries on a workflow instance as they land in the dataset.
|
|
4411
|
+
|
|
4412
|
+
```
|
|
4413
|
+
USAGE
|
|
4414
|
+
$ sanity workflows tail INSTANCEID [--tag <value>]
|
|
4415
|
+
|
|
4416
|
+
ARGUMENTS
|
|
4417
|
+
INSTANCEID Workflow instance id to tail.
|
|
4418
|
+
|
|
4419
|
+
FLAGS
|
|
4420
|
+
--tag=<value> Workflow environment tag (e.g. prod, test) — an optional query filter that also narrows which resources
|
|
4421
|
+
are searched; omit to span them all.
|
|
4422
|
+
|
|
4423
|
+
DESCRIPTION
|
|
4424
|
+
Stream new history entries on a workflow instance as they land in the dataset.
|
|
4425
|
+
|
|
4426
|
+
EXAMPLES
|
|
4427
|
+
$ sanity workflows tail wf-instance.abc123
|
|
4428
|
+
```
|
|
4429
|
+
|
|
3948
4430
|
<!-- commandsstop -->
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { formatDateTime, parseDateOnly } from '@sanity/cli-core/dates';
|
|
3
4
|
import { select } from '@sanity/cli-core/ux';
|
|
4
5
|
import { assertDatasetExists } from '../../actions/backup/assertDatasetExist.js';
|
|
5
6
|
import { promptForProject } from '../../prompts/promptForProject.js';
|
|
6
7
|
import { listBackups } from '../../services/backup.js';
|
|
7
8
|
import { listDatasets } from '../../services/datasets.js';
|
|
8
|
-
import { formatDateTime, parseDateOnly } from '../../util/dates.js';
|
|
9
9
|
import { Table } from '../../util/responsiveTable.js';
|
|
10
10
|
import { getProjectIdFlag } from '../../util/sharedFlags.js';
|
|
11
11
|
const listBackupDebug = subdebug('backup:list');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/backups/list.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {formatDateTime, parseDateOnly} from '../../util/dates.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listBackupDebug = subdebug('backup:list')\n\nconst DEFAULT_LIST_BACKUP_LIMIT = 30\n\ntype ListBackupRequestQueryParams = {\n after?: string\n before?: string\n limit: string\n}\n\nexport class ListBackupCommand extends SanityCommand<typeof ListBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to list backups for',\n required: false,\n }),\n }\n\n static override description = 'List available backups for a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List backups for a dataset interactively',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'List backups for the production dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --limit 50',\n description: 'List up to 50 backups for the production dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --after 2024-01-31 --limit 10',\n description: 'List up to 10 backups created after 2024-01-31',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list backups for',\n semantics: 'override',\n }),\n after: Flags.string({\n description: 'Only return backups after this date (inclusive, YYYY-MM-DD format)',\n }),\n before: Flags.string({\n description: 'Only return backups before this date (exclusive, YYYY-MM-DD format)',\n }),\n limit: Flags.integer({\n char: 'l',\n default: DEFAULT_LIST_BACKUP_LIMIT,\n description: 'Maximum number of backups returned',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:list']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(ListBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n listBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset, this.output)\n } else if (this.isUnattended()) {\n this.error('Dataset is required in unattended mode. Pass it as the `<dataset>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n } else {\n dataset = await this.promptForDataset(datasets)\n }\n\n // Validate date flags\n if (flags.before || flags.after) {\n try {\n const parsedBefore = this.processDateFlag(flags.before, 'before')\n const parsedAfter = this.processDateFlag(flags.after, 'after')\n\n if (parsedAfter && parsedBefore && parsedAfter.getTime() > parsedBefore.getTime()) {\n this.error('--after date must be before --before', {exit: exitCodes.RUNTIME_ERROR})\n }\n } catch (err) {\n this.error(`Parsing date flags: ${err instanceof Error ? err.message : err}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n // Validate limit flag\n if (flags.limit < 1 || flags.limit > Number.MAX_SAFE_INTEGER) {\n this.error(`Parsing --limit: must be an integer between 1 and ${Number.MAX_SAFE_INTEGER}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const query: ListBackupRequestQueryParams = {\n limit: flags.limit.toString(),\n }\n\n if (flags.after) {\n query.after = flags.after\n }\n\n if (flags.before) {\n query.before = flags.before\n }\n\n try {\n const response = await listBackups({\n after: flags.after,\n before: flags.before,\n datasetName: dataset,\n limit: flags.limit,\n projectId,\n })\n\n if (response.backups.length === 0) {\n this.log('No backups found.')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'resource', title: 'RESOURCE'},\n {alignment: 'left', name: 'createdAt', title: 'CREATED AT'},\n {alignment: 'left', name: 'backupId', title: 'BACKUP ID'},\n ],\n })\n\n for (const backup of response.backups) {\n const {createdAt, id} = backup\n table.addRow({\n backupId: id,\n createdAt: formatDateTime(createdAt),\n resource: 'Dataset',\n })\n }\n\n this.log(table.render())\n\n listBackupDebug(\n `Successfully listed ${response.backups.length} backups for dataset ${dataset}`,\n )\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n listBackupDebug(`Failed to list backups for dataset ${dataset}:`, error)\n this.error(`List dataset backup failed: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n\n private processDateFlag(date: string | undefined, flagName: string): Date | undefined {\n if (!date) return undefined\n const parsedDate = parseDateOnly(date)\n if (parsedDate) {\n return parsedDate\n }\n\n throw new Error(`Invalid date format for '--${flagName}' flag. Use YYYY-MM-DD`)\n }\n\n private async promptForDataset(datasets: DatasetsResponse): Promise<string> {\n try {\n const choices = datasets.map((dataset) => ({\n name: dataset.name,\n value: dataset.name,\n }))\n\n return select({\n choices,\n message: 'Select the dataset name:',\n })\n } catch (error) {\n listBackupDebug(`Error selecting dataset`, error)\n this.error(`Failed to select dataset:\\n${error instanceof Error ? error.message : error}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","select","assertDatasetExists","promptForProject","listBackups","listDatasets","formatDateTime","parseDateOnly","Table","getProjectIdFlag","listBackupDebug","DEFAULT_LIST_BACKUP_LIMIT","ListBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","after","before","limit","integer","char","default","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","RUNTIME_ERROR","length","output","isUnattended","USAGE_ERROR","promptForDataset","parsedBefore","processDateFlag","parsedAfter","getTime","err","Number","MAX_SAFE_INTEGER","query","toString","response","datasetName","backups","log","table","columns","alignment","name","title","backup","createdAt","id","addRow","backupId","resource","render","date","flagName","undefined","parsedDate","choices","map","value"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/backups/list.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {formatDateTime, parseDateOnly} from '@sanity/cli-core/dates'\nimport {select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst listBackupDebug = subdebug('backup:list')\n\nconst DEFAULT_LIST_BACKUP_LIMIT = 30\n\ntype ListBackupRequestQueryParams = {\n after?: string\n before?: string\n limit: string\n}\n\nexport class ListBackupCommand extends SanityCommand<typeof ListBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to list backups for',\n required: false,\n }),\n }\n\n static override description = 'List available backups for a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List backups for a dataset interactively',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'List backups for the production dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --limit 50',\n description: 'List up to 50 backups for the production dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --after 2024-01-31 --limit 10',\n description: 'List up to 10 backups created after 2024-01-31',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to list backups for',\n semantics: 'override',\n }),\n after: Flags.string({\n description: 'Only return backups after this date (inclusive, YYYY-MM-DD format)',\n }),\n before: Flags.string({\n description: 'Only return backups before this date (exclusive, YYYY-MM-DD format)',\n }),\n limit: Flags.integer({\n char: 'l',\n default: DEFAULT_LIST_BACKUP_LIMIT,\n description: 'Maximum number of backups returned',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:list']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(ListBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n listBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset, this.output)\n } else if (this.isUnattended()) {\n this.error('Dataset is required in unattended mode. Pass it as the `<dataset>` argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n } else {\n dataset = await this.promptForDataset(datasets)\n }\n\n // Validate date flags\n if (flags.before || flags.after) {\n try {\n const parsedBefore = this.processDateFlag(flags.before, 'before')\n const parsedAfter = this.processDateFlag(flags.after, 'after')\n\n if (parsedAfter && parsedBefore && parsedAfter.getTime() > parsedBefore.getTime()) {\n this.error('--after date must be before --before', {exit: exitCodes.RUNTIME_ERROR})\n }\n } catch (err) {\n this.error(`Parsing date flags: ${err instanceof Error ? err.message : err}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n // Validate limit flag\n if (flags.limit < 1 || flags.limit > Number.MAX_SAFE_INTEGER) {\n this.error(`Parsing --limit: must be an integer between 1 and ${Number.MAX_SAFE_INTEGER}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const query: ListBackupRequestQueryParams = {\n limit: flags.limit.toString(),\n }\n\n if (flags.after) {\n query.after = flags.after\n }\n\n if (flags.before) {\n query.before = flags.before\n }\n\n try {\n const response = await listBackups({\n after: flags.after,\n before: flags.before,\n datasetName: dataset,\n limit: flags.limit,\n projectId,\n })\n\n if (response.backups.length === 0) {\n this.log('No backups found.')\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'resource', title: 'RESOURCE'},\n {alignment: 'left', name: 'createdAt', title: 'CREATED AT'},\n {alignment: 'left', name: 'backupId', title: 'BACKUP ID'},\n ],\n })\n\n for (const backup of response.backups) {\n const {createdAt, id} = backup\n table.addRow({\n backupId: id,\n createdAt: formatDateTime(createdAt),\n resource: 'Dataset',\n })\n }\n\n this.log(table.render())\n\n listBackupDebug(\n `Successfully listed ${response.backups.length} backups for dataset ${dataset}`,\n )\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n listBackupDebug(`Failed to list backups for dataset ${dataset}:`, error)\n this.error(`List dataset backup failed: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n\n private processDateFlag(date: string | undefined, flagName: string): Date | undefined {\n if (!date) return undefined\n const parsedDate = parseDateOnly(date)\n if (parsedDate) {\n return parsedDate\n }\n\n throw new Error(`Invalid date format for '--${flagName}' flag. Use YYYY-MM-DD`)\n }\n\n private async promptForDataset(datasets: DatasetsResponse): Promise<string> {\n try {\n const choices = datasets.map((dataset) => ({\n name: dataset.name,\n value: dataset.name,\n }))\n\n return select({\n choices,\n message: 'Select the dataset name:',\n })\n } catch (error) {\n listBackupDebug(`Error selecting dataset`, error)\n this.error(`Failed to select dataset:\\n${error instanceof Error ? error.message : error}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","formatDateTime","parseDateOnly","select","assertDatasetExists","promptForProject","listBackups","listDatasets","Table","getProjectIdFlag","listBackupDebug","DEFAULT_LIST_BACKUP_LIMIT","ListBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","after","before","limit","integer","char","default","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","RUNTIME_ERROR","length","output","isUnattended","USAGE_ERROR","promptForDataset","parsedBefore","processDateFlag","parsedAfter","getTime","err","Number","MAX_SAFE_INTEGER","query","toString","response","datasetName","backups","log","table","columns","alignment","name","title","backup","createdAt","id","addRow","backupId","resource","render","date","flagName","undefined","parsedDate","choices","map","value"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { styleText } from 'node:util';
|
|
|
2
2
|
import { Args, Flags } from '@oclif/core';
|
|
3
3
|
import { exit } from '@oclif/core/errors';
|
|
4
4
|
import { exitCodes } from '@sanity/cli-core';
|
|
5
|
+
import { formatDuration, formatTimeAgo } from '@sanity/cli-core/dates';
|
|
5
6
|
import { subdebug } from '@sanity/cli-core/debug';
|
|
6
7
|
import { getCliExecutionContext } from '@sanity/cli-core/executionContext';
|
|
7
8
|
import { SanityCommand } from '@sanity/cli-core/SanityCommand';
|
|
@@ -11,7 +12,6 @@ import { promptForDataset } from '../../prompts/promptForDataset.js';
|
|
|
11
12
|
import { promptForDatasetName } from '../../prompts/promptForDatasetName.js';
|
|
12
13
|
import { promptForProject } from '../../prompts/promptForProject.js';
|
|
13
14
|
import { copyDataset, followCopyJobProgress, listDatasetCopyJobs, listDatasets } from '../../services/datasets.js';
|
|
14
|
-
import { formatDuration, formatTimeAgo } from '../../util/dates.js';
|
|
15
15
|
import { formatCliErrorMessages } from '../../util/formatCliErrorMessages.js';
|
|
16
16
|
import { Table } from '../../util/responsiveTable.js';
|
|
17
17
|
import { getProjectIdFlag } from '../../util/sharedFlags.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/datasets/copy.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exit} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\nimport {subdebug} from '@sanity/cli-core/debug'\nimport {getCliExecutionContext} from '@sanity/cli-core/executionContext'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {spinner} from '@sanity/cli-core/ux'\n\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {\n copyDataset,\n type CopyJobProgressEvent,\n type DatasetCopyJob,\n followCopyJobProgress,\n listDatasetCopyJobs,\n listDatasets,\n} from '../../services/datasets.js'\nimport {formatDuration, formatTimeAgo} from '../../util/dates.js'\nimport {formatCliErrorMessages} from '../../util/formatCliErrorMessages.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst copyDatasetDebug = subdebug('dataset:copy')\n\nexport class CopyDatasetCommand extends SanityCommand<typeof CopyDatasetCommand> {\n static override args = {\n source: Args.string({\n description: 'Name of the dataset to copy from',\n required: false,\n }),\n target: Args.string({\n description: 'Name of the dataset to copy to',\n required: false,\n }),\n }\n\n static override description = 'Copy a dataset or manage copy jobs'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively copy a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> source-dataset',\n description: 'Copy from source-dataset (prompts for target)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> source-dataset target-dataset',\n description: 'Copy from source-dataset to target-dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --skip-history source target',\n description: 'Copy without preserving document history (faster for large datasets)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --skip-content-releases source target',\n description: 'Copy without content release documents',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --detach source target',\n description: 'Start copy job without waiting for completion',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --attach <job-id>',\n description: 'Attach to a running copy job to follow progress',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --list',\n description: 'List all dataset copy jobs',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --list --offset 2 --limit 10',\n description: 'List copy jobs with pagination',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to copy dataset in',\n semantics: 'override',\n }),\n attach: Flags.string({\n description: 'Attach to the running copy process to show progress',\n exclusive: ['list', 'detach', 'skip-history'],\n required: false,\n }),\n detach: Flags.boolean({\n description: 'Start the copy without waiting for it to finish',\n exclusive: ['list', 'attach'],\n required: false,\n }),\n limit: Flags.integer({\n dependsOn: ['list'],\n description: 'Maximum number of jobs returned (default 10, max 1000)',\n max: 1000,\n required: false,\n }),\n list: Flags.boolean({\n description: 'Lists all dataset copy jobs',\n exclusive: ['attach', 'detach', 'skip-history'],\n required: false,\n }),\n offset: Flags.integer({\n dependsOn: ['list'],\n description: 'Start position in the list of jobs (default 0)',\n required: false,\n }),\n 'skip-content-releases': Flags.boolean({\n description: \"Don't copy content release documents to the target dataset\",\n exclusive: ['list', 'attach'],\n required: false,\n }),\n 'skip-history': Flags.boolean({\n description: \"Don't preserve document history on copy\",\n exclusive: ['list', 'attach'],\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:copy']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CopyDatasetCommand)\n\n if (!flags.list && !flags.attach && this.isUnattended()) {\n const errors: string[] = []\n\n if (!args.source) {\n errors.push('Source dataset is required. Pass it as the `<source>` argument.')\n }\n if (!args.target) {\n errors.push('Target dataset is required. Pass it as the `<target>` argument.')\n }\n\n if (errors.length > 0) {\n this.output.error(formatCliErrorMessages(errors), {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'create', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n // Route to appropriate mode\n if (flags.list) {\n return this.handleListMode(projectId, flags)\n }\n\n if (flags.attach) {\n return this.handleAttachMode(projectId, flags.attach)\n }\n\n return this.handleCopyMode(projectId, args, flags)\n }\n\n private displayCopyJobsTable(jobs: DatasetCopyJob[]): void {\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'Job ID'},\n {alignment: 'left', name: 'sourceDataset', title: 'Source Dataset'},\n {alignment: 'left', name: 'targetDataset', title: 'Target Dataset'},\n {alignment: 'left', name: 'state', title: 'State'},\n {alignment: 'left', name: 'withHistory', title: 'With history'},\n {alignment: 'left', name: 'timeStarted', title: 'Time started'},\n {alignment: 'left', name: 'timeTaken', title: 'Time taken'},\n ],\n title: 'Dataset copy jobs for this project in descending order',\n })\n\n for (const job of jobs) {\n const {createdAt, id, sourceDataset, state, targetDataset, updatedAt, withHistory} = job\n\n let timeStarted = ''\n if (createdAt !== '') {\n timeStarted = formatTimeAgo(new Date(createdAt))\n }\n\n let timeTaken = ''\n if (createdAt !== '' && updatedAt !== '') {\n timeTaken = formatDuration(new Date(updatedAt).getTime() - new Date(createdAt).getTime())\n }\n\n let color: '' | 'green' | 'red' | 'yellow'\n switch (state) {\n case 'completed': {\n color = 'green'\n break\n }\n case 'failed': {\n color = 'red'\n break\n }\n case 'pending': {\n color = 'yellow'\n break\n }\n default: {\n color = ''\n }\n }\n\n table.addRow(\n {\n id,\n sourceDataset,\n state,\n targetDataset,\n timeStarted,\n timeTaken,\n withHistory,\n },\n {color},\n )\n }\n\n this.output.log(table.render())\n }\n\n private async handleAttachMode(projectId: string, jobId: string): Promise<void> {\n copyDatasetDebug('Attaching to copy job %s', jobId)\n\n if (jobId.trim() === '') {\n return this.output.error('Please supply a valid jobId', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n try {\n await this.subscribeToProgress(projectId, jobId)\n this.output.log(`Job ${styleText('green', jobId)} completed`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to attach to copy job: %s', message, error)\n return this.output.error(`Failed to attach to copy job: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async handleCopyMode(\n projectId: string,\n args: {source?: string; target?: string},\n flags: {detach?: boolean; 'skip-content-releases'?: boolean; 'skip-history'?: boolean},\n ): Promise<void> {\n copyDatasetDebug('Starting copy mode')\n\n const skipHistory = Boolean(flags['skip-history'])\n const skipContentReleases = Boolean(flags['skip-content-releases'])\n\n // Surfaced before any prompting so the flag is still actionable: a copy job\n // can't be canceled once started, so mentioning it after the job kicks off\n // leaves nothing to decide.\n if (!skipHistory) {\n this.output.log(\n `Note: You can run this command with flag '--skip-history'. The flag will reduce copy time in larger datasets.`,\n )\n }\n\n // Get and validate source dataset\n let sourceDataset = args.source\n if (sourceDataset) {\n const nameError = validateDatasetName(sourceDataset)\n if (nameError) {\n return this.output.error(nameError, {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n let datasetsResponse\n try {\n datasetsResponse = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to fetch datasets: %s', message, error)\n return this.output.error(`Failed to fetch datasets: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const datasetNames = new Set(datasetsResponse.map((ds) => ds.name))\n\n // Prompt for source if not provided\n if (!sourceDataset) {\n sourceDataset = await promptForDataset({\n datasets: datasetsResponse,\n })\n }\n\n if (!datasetNames.has(sourceDataset)) {\n return this.output.error(`Source dataset \"${sourceDataset}\" doesn't exist`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // Get and validate target dataset\n let targetDataset = args.target\n if (targetDataset) {\n const nameError = validateDatasetName(targetDataset)\n if (nameError) {\n return this.output.error(nameError, {exit: exitCodes.USAGE_ERROR})\n }\n } else {\n targetDataset = await promptForDatasetName({\n message: 'Target dataset name:',\n })\n }\n\n if (datasetNames.has(targetDataset)) {\n return this.output.error(`Target dataset \"${targetDataset}\" already exists`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // Start the copy job\n try {\n this.output.log(\n `Copying dataset ${styleText('green', sourceDataset)} to ${styleText('green', targetDataset)}...`,\n )\n\n const response = await copyDataset({\n projectId,\n skipContentReleases,\n skipHistory,\n sourceDataset,\n targetDataset,\n })\n\n this.output.log(`Job ${styleText('green', response.jobId)} started`)\n\n if (flags.detach) {\n return\n }\n\n await this.subscribeToProgress(projectId, response.jobId)\n this.output.log(`Job ${styleText('green', response.jobId)} completed`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Dataset copying failed: %s', message, error)\n return this.output.error(`Dataset copying failed: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async handleListMode(\n projectId: string,\n flags: {limit?: number; offset?: number},\n ): Promise<void> {\n copyDatasetDebug('Listing dataset copy jobs')\n\n try {\n const jobs = await listDatasetCopyJobs({\n limit: flags.limit,\n offset: flags.offset,\n projectId,\n })\n\n if (jobs.length === 0) {\n this.output.log(\"This project doesn't have any dataset copy jobs\")\n return\n }\n\n this.displayCopyJobsTable(jobs)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to list dataset copy jobs: %s', message, error)\n return this.output.error(`Failed to list dataset copy jobs: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async subscribeToProgress(projectId: string, jobId: string): Promise<void> {\n const spin = spinner('').start()\n const hasCliExecutionContext = Boolean(getCliExecutionContext())\n\n return new Promise<void>((resolve, reject) => {\n const sigintHandler = () => {\n subscription.unsubscribe()\n spin.fail('Copy interrupted.')\n exit(130)\n }\n\n const subscription = followCopyJobProgress({jobId, projectId}).subscribe({\n complete: () => {\n if (!hasCliExecutionContext) process.off('SIGINT', sigintHandler)\n spin.succeed('Copy finished.')\n resolve()\n },\n error: (err) => {\n if (!hasCliExecutionContext) process.off('SIGINT', sigintHandler)\n spin.fail('Copy failed.')\n reject(err)\n },\n next: (event: CopyJobProgressEvent) => {\n if (typeof event.progress === 'number') {\n spin.text = `Copy in progress: ${event.progress}%`\n }\n },\n })\n\n if (!hasCliExecutionContext) process.once('SIGINT', sigintHandler)\n })\n }\n}\n"],"names":["styleText","Args","Flags","exit","exitCodes","subdebug","getCliExecutionContext","SanityCommand","spinner","validateDatasetName","promptForDataset","promptForDatasetName","promptForProject","copyDataset","followCopyJobProgress","listDatasetCopyJobs","listDatasets","formatDuration","formatTimeAgo","formatCliErrorMessages","Table","getProjectIdFlag","copyDatasetDebug","CopyDatasetCommand","args","source","string","description","required","target","examples","command","flags","semantics","attach","exclusive","detach","boolean","limit","integer","dependsOn","max","list","offset","hiddenAliases","run","parse","isUnattended","errors","push","length","output","error","USAGE_ERROR","projectId","getProjectId","fallback","requiredPermissions","grant","permission","handleListMode","handleAttachMode","handleCopyMode","displayCopyJobsTable","jobs","table","columns","alignment","name","title","job","createdAt","id","sourceDataset","state","targetDataset","updatedAt","withHistory","timeStarted","Date","timeTaken","getTime","color","addRow","log","render","jobId","trim","RUNTIME_ERROR","subscribeToProgress","message","Error","String","skipHistory","Boolean","skipContentReleases","nameError","datasetsResponse","datasetNames","Set","map","ds","datasets","has","response","spin","start","hasCliExecutionContext","Promise","resolve","reject","sigintHandler","subscription","unsubscribe","fail","subscribe","complete","process","off","succeed","err","next","event","progress","text","once"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAQC,IAAI,QAAO,qBAAoB;AACvC,SAAQC,SAAS,QAAO,mBAAkB;AAC1C,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,sBAAsB,QAAO,oCAAmC;AACxE,SAAQC,aAAa,QAAO,iCAAgC;AAC5D,SAAQC,OAAO,QAAO,sBAAqB;AAE3C,SAAQC,mBAAmB,QAAO,+CAA8C;AAChF,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,oBAAoB,QAAO,wCAAuC;AAC1E,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SACEC,WAAW,EAGXC,qBAAqB,EACrBC,mBAAmB,EACnBC,YAAY,QACP,6BAA4B;AACnC,SAAQC,cAAc,EAAEC,aAAa,QAAO,sBAAqB;AACjE,SAAQC,sBAAsB,QAAO,uCAAsC;AAC3E,SAAQC,KAAK,QAAO,gCAA+B;AACnD,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,MAAMC,mBAAmBjB,SAAS;AAElC,OAAO,MAAMkB,2BAA2BhB;IACtC,OAAgBiB,OAAO;QACrBC,QAAQxB,KAAKyB,MAAM,CAAC;YAClBC,aAAa;YACbC,UAAU;QACZ;QACAC,QAAQ5B,KAAKyB,MAAM,CAAC;YAClBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,qCAAoC;IAElE,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtB,GAAGX,iBAAiB;YAClBM,aAAa;YACbM,WAAW;QACb,EAAE;QACFC,QAAQhC,MAAMwB,MAAM,CAAC;YACnBC,aAAa;YACbQ,WAAW;gBAAC;gBAAQ;gBAAU;aAAe;YAC7CP,UAAU;QACZ;QACAQ,QAAQlC,MAAMmC,OAAO,CAAC;YACpBV,aAAa;YACbQ,WAAW;gBAAC;gBAAQ;aAAS;YAC7BP,UAAU;QACZ;QACAU,OAAOpC,MAAMqC,OAAO,CAAC;YACnBC,WAAW;gBAAC;aAAO;YACnBb,aAAa;YACbc,KAAK;YACLb,UAAU;QACZ;QACAc,MAAMxC,MAAMmC,OAAO,CAAC;YAClBV,aAAa;YACbQ,WAAW;gBAAC;gBAAU;gBAAU;aAAe;YAC/CP,UAAU;QACZ;QACAe,QAAQzC,MAAMqC,OAAO,CAAC;YACpBC,WAAW;gBAAC;aAAO;YACnBb,aAAa;YACbC,UAAU;QACZ;QACA,yBAAyB1B,MAAMmC,OAAO,CAAC;YACrCV,aAAa;YACbQ,WAAW;gBAAC;gBAAQ;aAAS;YAC7BP,UAAU;QACZ;QACA,gBAAgB1B,MAAMmC,OAAO,CAAC;YAC5BV,aAAa;YACbQ,WAAW;gBAAC;gBAAQ;aAAS;YAC7BP,UAAU;QACZ;IACF,EAAC;IAED,OAAgBgB,gBAA0B;QAAC;KAAe,CAAA;IAE1D,MAAaC,MAAqB;QAChC,MAAM,EAACrB,IAAI,EAAEQ,KAAK,EAAC,GAAG,MAAM,IAAI,CAACc,KAAK,CAACvB;QAEvC,IAAI,CAACS,MAAMU,IAAI,IAAI,CAACV,MAAME,MAAM,IAAI,IAAI,CAACa,YAAY,IAAI;YACvD,MAAMC,SAAmB,EAAE;YAE3B,IAAI,CAACxB,KAAKC,MAAM,EAAE;gBAChBuB,OAAOC,IAAI,CAAC;YACd;YACA,IAAI,CAACzB,KAAKK,MAAM,EAAE;gBAChBmB,OAAOC,IAAI,CAAC;YACd;YAEA,IAAID,OAAOE,MAAM,GAAG,GAAG;gBACrB,IAAI,CAACC,MAAM,CAACC,KAAK,CAACjC,uBAAuB6B,SAAS;oBAAC7C,MAAMC,UAAUiD,WAAW;gBAAA;YAChF;QACF;QAEA,MAAMC,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,UAAU,IACR5C,iBAAiB;oBACf6C,qBAAqB;wBACnB;4BAACC,OAAO;4BAAQC,YAAY;wBAAyB;wBACrD;4BAACD,OAAO;4BAAUC,YAAY;wBAAyB;qBACxD;gBACH;QACJ;QAEA,4BAA4B;QAC5B,IAAI3B,MAAMU,IAAI,EAAE;YACd,OAAO,IAAI,CAACkB,cAAc,CAACN,WAAWtB;QACxC;QAEA,IAAIA,MAAME,MAAM,EAAE;YAChB,OAAO,IAAI,CAAC2B,gBAAgB,CAACP,WAAWtB,MAAME,MAAM;QACtD;QAEA,OAAO,IAAI,CAAC4B,cAAc,CAACR,WAAW9B,MAAMQ;IAC9C;IAEQ+B,qBAAqBC,IAAsB,EAAQ;QACzD,MAAMC,QAAQ,IAAI7C,MAAM;YACtB8C,SAAS;gBACP;oBAACC,WAAW;oBAAQC,MAAM;oBAAMC,OAAO;gBAAQ;gBAC/C;oBAACF,WAAW;oBAAQC,MAAM;oBAAiBC,OAAO;gBAAgB;gBAClE;oBAACF,WAAW;oBAAQC,MAAM;oBAAiBC,OAAO;gBAAgB;gBAClE;oBAACF,WAAW;oBAAQC,MAAM;oBAASC,OAAO;gBAAO;gBACjD;oBAACF,WAAW;oBAAQC,MAAM;oBAAeC,OAAO;gBAAc;gBAC9D;oBAACF,WAAW;oBAAQC,MAAM;oBAAeC,OAAO;gBAAc;gBAC9D;oBAACF,WAAW;oBAAQC,MAAM;oBAAaC,OAAO;gBAAY;aAC3D;YACDA,OAAO;QACT;QAEA,KAAK,MAAMC,OAAON,KAAM;YACtB,MAAM,EAACO,SAAS,EAAEC,EAAE,EAAEC,aAAa,EAAEC,KAAK,EAAEC,aAAa,EAAEC,SAAS,EAAEC,WAAW,EAAC,GAAGP;YAErF,IAAIQ,cAAc;YAClB,IAAIP,cAAc,IAAI;gBACpBO,cAAc5D,cAAc,IAAI6D,KAAKR;YACvC;YAEA,IAAIS,YAAY;YAChB,IAAIT,cAAc,MAAMK,cAAc,IAAI;gBACxCI,YAAY/D,eAAe,IAAI8D,KAAKH,WAAWK,OAAO,KAAK,IAAIF,KAAKR,WAAWU,OAAO;YACxF;YAEA,IAAIC;YACJ,OAAQR;gBACN,KAAK;oBAAa;wBAChBQ,QAAQ;wBACR;oBACF;gBACA,KAAK;oBAAU;wBACbA,QAAQ;wBACR;oBACF;gBACA,KAAK;oBAAW;wBACdA,QAAQ;wBACR;oBACF;gBACA;oBAAS;wBACPA,QAAQ;oBACV;YACF;YAEAjB,MAAMkB,MAAM,CACV;gBACEX;gBACAC;gBACAC;gBACAC;gBACAG;gBACAE;gBACAH;YACF,GACA;gBAACK;YAAK;QAEV;QAEA,IAAI,CAAC/B,MAAM,CAACiC,GAAG,CAACnB,MAAMoB,MAAM;IAC9B;IAEA,MAAcxB,iBAAiBP,SAAiB,EAAEgC,KAAa,EAAiB;QAC9EhE,iBAAiB,4BAA4BgE;QAE7C,IAAIA,MAAMC,IAAI,OAAO,IAAI;YACvB,OAAO,IAAI,CAACpC,MAAM,CAACC,KAAK,CAAC,+BAA+B;gBAACjD,MAAMC,UAAUoF,aAAa;YAAA;QACxF;QAEA,IAAI;YACF,MAAM,IAAI,CAACC,mBAAmB,CAACnC,WAAWgC;YAC1C,IAAI,CAACnC,MAAM,CAACiC,GAAG,CAAC,CAAC,IAAI,EAAEpF,UAAU,SAASsF,OAAO,UAAU,CAAC;QAC9D,EAAE,OAAOlC,OAAO;YACd,MAAMsC,UAAUtC,iBAAiBuC,QAAQvC,MAAMsC,OAAO,GAAGE,OAAOxC;YAChE9B,iBAAiB,oCAAoCoE,SAAStC;YAC9D,OAAO,IAAI,CAACD,MAAM,CAACC,KAAK,CAAC,CAAC,8BAA8B,EAAEsC,SAAS,EAAE;gBACnEvF,MAAMC,UAAUoF,aAAa;YAC/B;QACF;IACF;IAEA,MAAc1B,eACZR,SAAiB,EACjB9B,IAAwC,EACxCQ,KAAsF,EACvE;QACfV,iBAAiB;QAEjB,MAAMuE,cAAcC,QAAQ9D,KAAK,CAAC,eAAe;QACjD,MAAM+D,sBAAsBD,QAAQ9D,KAAK,CAAC,wBAAwB;QAElE,4EAA4E;QAC5E,2EAA2E;QAC3E,4BAA4B;QAC5B,IAAI,CAAC6D,aAAa;YAChB,IAAI,CAAC1C,MAAM,CAACiC,GAAG,CACb,CAAC,6GAA6G,CAAC;QAEnH;QAEA,kCAAkC;QAClC,IAAIX,gBAAgBjD,KAAKC,MAAM;QAC/B,IAAIgD,eAAe;YACjB,MAAMuB,YAAYvF,oBAAoBgE;YACtC,IAAIuB,WAAW;gBACb,OAAO,IAAI,CAAC7C,MAAM,CAACC,KAAK,CAAC4C,WAAW;oBAAC7F,MAAMC,UAAUiD,WAAW;gBAAA;YAClE;QACF;QAEA,IAAI4C;QACJ,IAAI;YACFA,mBAAmB,MAAMjF,aAAasC;QACxC,EAAE,OAAOF,OAAO;YACd,MAAMsC,UAAUtC,iBAAiBuC,QAAQvC,MAAMsC,OAAO,GAAGE,OAAOxC;YAChE9B,iBAAiB,gCAAgCoE,SAAStC;YAC1D,OAAO,IAAI,CAACD,MAAM,CAACC,KAAK,CAAC,CAAC,0BAA0B,EAAEsC,SAAS,EAAE;gBAC/DvF,MAAMC,UAAUoF,aAAa;YAC/B;QACF;QAEA,MAAMU,eAAe,IAAIC,IAAIF,iBAAiBG,GAAG,CAAC,CAACC,KAAOA,GAAGjC,IAAI;QAEjE,oCAAoC;QACpC,IAAI,CAACK,eAAe;YAClBA,gBAAgB,MAAM/D,iBAAiB;gBACrC4F,UAAUL;YACZ;QACF;QAEA,IAAI,CAACC,aAAaK,GAAG,CAAC9B,gBAAgB;YACpC,OAAO,IAAI,CAACtB,MAAM,CAACC,KAAK,CAAC,CAAC,gBAAgB,EAAEqB,cAAc,eAAe,CAAC,EAAE;gBAC1EtE,MAAMC,UAAUoF,aAAa;YAC/B;QACF;QAEA,kCAAkC;QAClC,IAAIb,gBAAgBnD,KAAKK,MAAM;QAC/B,IAAI8C,eAAe;YACjB,MAAMqB,YAAYvF,oBAAoBkE;YACtC,IAAIqB,WAAW;gBACb,OAAO,IAAI,CAAC7C,MAAM,CAACC,KAAK,CAAC4C,WAAW;oBAAC7F,MAAMC,UAAUiD,WAAW;gBAAA;YAClE;QACF,OAAO;YACLsB,gBAAgB,MAAMhE,qBAAqB;gBACzC+E,SAAS;YACX;QACF;QAEA,IAAIQ,aAAaK,GAAG,CAAC5B,gBAAgB;YACnC,OAAO,IAAI,CAACxB,MAAM,CAACC,KAAK,CAAC,CAAC,gBAAgB,EAAEuB,cAAc,gBAAgB,CAAC,EAAE;gBAC3ExE,MAAMC,UAAUoF,aAAa;YAC/B;QACF;QAEA,qBAAqB;QACrB,IAAI;YACF,IAAI,CAACrC,MAAM,CAACiC,GAAG,CACb,CAAC,gBAAgB,EAAEpF,UAAU,SAASyE,eAAe,IAAI,EAAEzE,UAAU,SAAS2E,eAAe,GAAG,CAAC;YAGnG,MAAM6B,WAAW,MAAM3F,YAAY;gBACjCyC;gBACAyC;gBACAF;gBACApB;gBACAE;YACF;YAEA,IAAI,CAACxB,MAAM,CAACiC,GAAG,CAAC,CAAC,IAAI,EAAEpF,UAAU,SAASwG,SAASlB,KAAK,EAAE,QAAQ,CAAC;YAEnE,IAAItD,MAAMI,MAAM,EAAE;gBAChB;YACF;YAEA,MAAM,IAAI,CAACqD,mBAAmB,CAACnC,WAAWkD,SAASlB,KAAK;YACxD,IAAI,CAACnC,MAAM,CAACiC,GAAG,CAAC,CAAC,IAAI,EAAEpF,UAAU,SAASwG,SAASlB,KAAK,EAAE,UAAU,CAAC;QACvE,EAAE,OAAOlC,OAAO;YACd,MAAMsC,UAAUtC,iBAAiBuC,QAAQvC,MAAMsC,OAAO,GAAGE,OAAOxC;YAChE9B,iBAAiB,8BAA8BoE,SAAStC;YACxD,OAAO,IAAI,CAACD,MAAM,CAACC,KAAK,CAAC,CAAC,wBAAwB,EAAEsC,SAAS,EAAE;gBAC7DvF,MAAMC,UAAUoF,aAAa;YAC/B;QACF;IACF;IAEA,MAAc5B,eACZN,SAAiB,EACjBtB,KAAwC,EACzB;QACfV,iBAAiB;QAEjB,IAAI;YACF,MAAM0C,OAAO,MAAMjD,oBAAoB;gBACrCuB,OAAON,MAAMM,KAAK;gBAClBK,QAAQX,MAAMW,MAAM;gBACpBW;YACF;YAEA,IAAIU,KAAKd,MAAM,KAAK,GAAG;gBACrB,IAAI,CAACC,MAAM,CAACiC,GAAG,CAAC;gBAChB;YACF;YAEA,IAAI,CAACrB,oBAAoB,CAACC;QAC5B,EAAE,OAAOZ,OAAO;YACd,MAAMsC,UAAUtC,iBAAiBuC,QAAQvC,MAAMsC,OAAO,GAAGE,OAAOxC;YAChE9B,iBAAiB,wCAAwCoE,SAAStC;YAClE,OAAO,IAAI,CAACD,MAAM,CAACC,KAAK,CAAC,CAAC,kCAAkC,EAAEsC,SAAS,EAAE;gBACvEvF,MAAMC,UAAUoF,aAAa;YAC/B;QACF;IACF;IAEA,MAAcC,oBAAoBnC,SAAiB,EAAEgC,KAAa,EAAiB;QACjF,MAAMmB,OAAOjG,QAAQ,IAAIkG,KAAK;QAC9B,MAAMC,yBAAyBb,QAAQxF;QAEvC,OAAO,IAAIsG,QAAc,CAACC,SAASC;YACjC,MAAMC,gBAAgB;gBACpBC,aAAaC,WAAW;gBACxBR,KAAKS,IAAI,CAAC;gBACV/G,KAAK;YACP;YAEA,MAAM6G,eAAelG,sBAAsB;gBAACwE;gBAAOhC;YAAS,GAAG6D,SAAS,CAAC;gBACvEC,UAAU;oBACR,IAAI,CAACT,wBAAwBU,QAAQC,GAAG,CAAC,UAAUP;oBACnDN,KAAKc,OAAO,CAAC;oBACbV;gBACF;gBACAzD,OAAO,CAACoE;oBACN,IAAI,CAACb,wBAAwBU,QAAQC,GAAG,CAAC,UAAUP;oBACnDN,KAAKS,IAAI,CAAC;oBACVJ,OAAOU;gBACT;gBACAC,MAAM,CAACC;oBACL,IAAI,OAAOA,MAAMC,QAAQ,KAAK,UAAU;wBACtClB,KAAKmB,IAAI,GAAG,CAAC,kBAAkB,EAAEF,MAAMC,QAAQ,CAAC,CAAC,CAAC;oBACpD;gBACF;YACF;YAEA,IAAI,CAAChB,wBAAwBU,QAAQQ,IAAI,CAAC,UAAUd;QACtD;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/datasets/copy.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exit} from '@oclif/core/errors'\nimport {exitCodes} from '@sanity/cli-core'\nimport {formatDuration, formatTimeAgo} from '@sanity/cli-core/dates'\nimport {subdebug} from '@sanity/cli-core/debug'\nimport {getCliExecutionContext} from '@sanity/cli-core/executionContext'\nimport {SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {spinner} from '@sanity/cli-core/ux'\n\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {\n copyDataset,\n type CopyJobProgressEvent,\n type DatasetCopyJob,\n followCopyJobProgress,\n listDatasetCopyJobs,\n listDatasets,\n} from '../../services/datasets.js'\nimport {formatCliErrorMessages} from '../../util/formatCliErrorMessages.js'\nimport {Table} from '../../util/responsiveTable.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst copyDatasetDebug = subdebug('dataset:copy')\n\nexport class CopyDatasetCommand extends SanityCommand<typeof CopyDatasetCommand> {\n static override args = {\n source: Args.string({\n description: 'Name of the dataset to copy from',\n required: false,\n }),\n target: Args.string({\n description: 'Name of the dataset to copy to',\n required: false,\n }),\n }\n\n static override description = 'Copy a dataset or manage copy jobs'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively copy a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> source-dataset',\n description: 'Copy from source-dataset (prompts for target)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> source-dataset target-dataset',\n description: 'Copy from source-dataset to target-dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --skip-history source target',\n description: 'Copy without preserving document history (faster for large datasets)',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --skip-content-releases source target',\n description: 'Copy without content release documents',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --detach source target',\n description: 'Start copy job without waiting for completion',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --attach <job-id>',\n description: 'Attach to a running copy job to follow progress',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --list',\n description: 'List all dataset copy jobs',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --list --offset 2 --limit 10',\n description: 'List copy jobs with pagination',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to copy dataset in',\n semantics: 'override',\n }),\n attach: Flags.string({\n description: 'Attach to the running copy process to show progress',\n exclusive: ['list', 'detach', 'skip-history'],\n required: false,\n }),\n detach: Flags.boolean({\n description: 'Start the copy without waiting for it to finish',\n exclusive: ['list', 'attach'],\n required: false,\n }),\n limit: Flags.integer({\n dependsOn: ['list'],\n description: 'Maximum number of jobs returned (default 10, max 1000)',\n max: 1000,\n required: false,\n }),\n list: Flags.boolean({\n description: 'Lists all dataset copy jobs',\n exclusive: ['attach', 'detach', 'skip-history'],\n required: false,\n }),\n offset: Flags.integer({\n dependsOn: ['list'],\n description: 'Start position in the list of jobs (default 0)',\n required: false,\n }),\n 'skip-content-releases': Flags.boolean({\n description: \"Don't copy content release documents to the target dataset\",\n exclusive: ['list', 'attach'],\n required: false,\n }),\n 'skip-history': Flags.boolean({\n description: \"Don't preserve document history on copy\",\n exclusive: ['list', 'attach'],\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:copy']\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(CopyDatasetCommand)\n\n if (!flags.list && !flags.attach && this.isUnattended()) {\n const errors: string[] = []\n\n if (!args.source) {\n errors.push('Source dataset is required. Pass it as the `<source>` argument.')\n }\n if (!args.target) {\n errors.push('Target dataset is required. Pass it as the `<target>` argument.')\n }\n\n if (errors.length > 0) {\n this.output.error(formatCliErrorMessages(errors), {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'create', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n // Route to appropriate mode\n if (flags.list) {\n return this.handleListMode(projectId, flags)\n }\n\n if (flags.attach) {\n return this.handleAttachMode(projectId, flags.attach)\n }\n\n return this.handleCopyMode(projectId, args, flags)\n }\n\n private displayCopyJobsTable(jobs: DatasetCopyJob[]): void {\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'Job ID'},\n {alignment: 'left', name: 'sourceDataset', title: 'Source Dataset'},\n {alignment: 'left', name: 'targetDataset', title: 'Target Dataset'},\n {alignment: 'left', name: 'state', title: 'State'},\n {alignment: 'left', name: 'withHistory', title: 'With history'},\n {alignment: 'left', name: 'timeStarted', title: 'Time started'},\n {alignment: 'left', name: 'timeTaken', title: 'Time taken'},\n ],\n title: 'Dataset copy jobs for this project in descending order',\n })\n\n for (const job of jobs) {\n const {createdAt, id, sourceDataset, state, targetDataset, updatedAt, withHistory} = job\n\n let timeStarted = ''\n if (createdAt !== '') {\n timeStarted = formatTimeAgo(new Date(createdAt))\n }\n\n let timeTaken = ''\n if (createdAt !== '' && updatedAt !== '') {\n timeTaken = formatDuration(new Date(updatedAt).getTime() - new Date(createdAt).getTime())\n }\n\n let color: '' | 'green' | 'red' | 'yellow'\n switch (state) {\n case 'completed': {\n color = 'green'\n break\n }\n case 'failed': {\n color = 'red'\n break\n }\n case 'pending': {\n color = 'yellow'\n break\n }\n default: {\n color = ''\n }\n }\n\n table.addRow(\n {\n id,\n sourceDataset,\n state,\n targetDataset,\n timeStarted,\n timeTaken,\n withHistory,\n },\n {color},\n )\n }\n\n this.output.log(table.render())\n }\n\n private async handleAttachMode(projectId: string, jobId: string): Promise<void> {\n copyDatasetDebug('Attaching to copy job %s', jobId)\n\n if (jobId.trim() === '') {\n return this.output.error('Please supply a valid jobId', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n try {\n await this.subscribeToProgress(projectId, jobId)\n this.output.log(`Job ${styleText('green', jobId)} completed`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to attach to copy job: %s', message, error)\n return this.output.error(`Failed to attach to copy job: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async handleCopyMode(\n projectId: string,\n args: {source?: string; target?: string},\n flags: {detach?: boolean; 'skip-content-releases'?: boolean; 'skip-history'?: boolean},\n ): Promise<void> {\n copyDatasetDebug('Starting copy mode')\n\n const skipHistory = Boolean(flags['skip-history'])\n const skipContentReleases = Boolean(flags['skip-content-releases'])\n\n // Surfaced before any prompting so the flag is still actionable: a copy job\n // can't be canceled once started, so mentioning it after the job kicks off\n // leaves nothing to decide.\n if (!skipHistory) {\n this.output.log(\n `Note: You can run this command with flag '--skip-history'. The flag will reduce copy time in larger datasets.`,\n )\n }\n\n // Get and validate source dataset\n let sourceDataset = args.source\n if (sourceDataset) {\n const nameError = validateDatasetName(sourceDataset)\n if (nameError) {\n return this.output.error(nameError, {exit: exitCodes.USAGE_ERROR})\n }\n }\n\n let datasetsResponse\n try {\n datasetsResponse = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to fetch datasets: %s', message, error)\n return this.output.error(`Failed to fetch datasets: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const datasetNames = new Set(datasetsResponse.map((ds) => ds.name))\n\n // Prompt for source if not provided\n if (!sourceDataset) {\n sourceDataset = await promptForDataset({\n datasets: datasetsResponse,\n })\n }\n\n if (!datasetNames.has(sourceDataset)) {\n return this.output.error(`Source dataset \"${sourceDataset}\" doesn't exist`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // Get and validate target dataset\n let targetDataset = args.target\n if (targetDataset) {\n const nameError = validateDatasetName(targetDataset)\n if (nameError) {\n return this.output.error(nameError, {exit: exitCodes.USAGE_ERROR})\n }\n } else {\n targetDataset = await promptForDatasetName({\n message: 'Target dataset name:',\n })\n }\n\n if (datasetNames.has(targetDataset)) {\n return this.output.error(`Target dataset \"${targetDataset}\" already exists`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // Start the copy job\n try {\n this.output.log(\n `Copying dataset ${styleText('green', sourceDataset)} to ${styleText('green', targetDataset)}...`,\n )\n\n const response = await copyDataset({\n projectId,\n skipContentReleases,\n skipHistory,\n sourceDataset,\n targetDataset,\n })\n\n this.output.log(`Job ${styleText('green', response.jobId)} started`)\n\n if (flags.detach) {\n return\n }\n\n await this.subscribeToProgress(projectId, response.jobId)\n this.output.log(`Job ${styleText('green', response.jobId)} completed`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Dataset copying failed: %s', message, error)\n return this.output.error(`Dataset copying failed: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async handleListMode(\n projectId: string,\n flags: {limit?: number; offset?: number},\n ): Promise<void> {\n copyDatasetDebug('Listing dataset copy jobs')\n\n try {\n const jobs = await listDatasetCopyJobs({\n limit: flags.limit,\n offset: flags.offset,\n projectId,\n })\n\n if (jobs.length === 0) {\n this.output.log(\"This project doesn't have any dataset copy jobs\")\n return\n }\n\n this.displayCopyJobsTable(jobs)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n copyDatasetDebug('Failed to list dataset copy jobs: %s', message, error)\n return this.output.error(`Failed to list dataset copy jobs: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async subscribeToProgress(projectId: string, jobId: string): Promise<void> {\n const spin = spinner('').start()\n const hasCliExecutionContext = Boolean(getCliExecutionContext())\n\n return new Promise<void>((resolve, reject) => {\n const sigintHandler = () => {\n subscription.unsubscribe()\n spin.fail('Copy interrupted.')\n exit(130)\n }\n\n const subscription = followCopyJobProgress({jobId, projectId}).subscribe({\n complete: () => {\n if (!hasCliExecutionContext) process.off('SIGINT', sigintHandler)\n spin.succeed('Copy finished.')\n resolve()\n },\n error: (err) => {\n if (!hasCliExecutionContext) process.off('SIGINT', sigintHandler)\n spin.fail('Copy failed.')\n reject(err)\n },\n next: (event: CopyJobProgressEvent) => {\n if (typeof event.progress === 'number') {\n spin.text = `Copy in progress: ${event.progress}%`\n }\n },\n })\n\n if (!hasCliExecutionContext) process.once('SIGINT', sigintHandler)\n })\n }\n}\n"],"names":["styleText","Args","Flags","exit","exitCodes","formatDuration","formatTimeAgo","subdebug","getCliExecutionContext","SanityCommand","spinner","validateDatasetName","promptForDataset","promptForDatasetName","promptForProject","copyDataset","followCopyJobProgress","listDatasetCopyJobs","listDatasets","formatCliErrorMessages","Table","getProjectIdFlag","copyDatasetDebug","CopyDatasetCommand","args","source","string","description","required","target","examples","command","flags","semantics","attach","exclusive","detach","boolean","limit","integer","dependsOn","max","list","offset","hiddenAliases","run","parse","isUnattended","errors","push","length","output","error","USAGE_ERROR","projectId","getProjectId","fallback","requiredPermissions","grant","permission","handleListMode","handleAttachMode","handleCopyMode","displayCopyJobsTable","jobs","table","columns","alignment","name","title","job","createdAt","id","sourceDataset","state","targetDataset","updatedAt","withHistory","timeStarted","Date","timeTaken","getTime","color","addRow","log","render","jobId","trim","RUNTIME_ERROR","subscribeToProgress","message","Error","String","skipHistory","Boolean","skipContentReleases","nameError","datasetsResponse","datasetNames","Set","map","ds","datasets","has","response","spin","start","hasCliExecutionContext","Promise","resolve","reject","sigintHandler","subscription","unsubscribe","fail","subscribe","complete","process","off","succeed","err","next","event","progress","text","once"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/extractDocumentsFromNdjsonOrTarball.ts"],"sourcesContent":["import path from 'node:path'\nimport readline from 'node:readline'\nimport {Readable
|
|
1
|
+
{"version":3,"sources":["../../src/util/extractDocumentsFromNdjsonOrTarball.ts"],"sourcesContent":["import path from 'node:path'\nimport readline from 'node:readline'\nimport {Readable} from 'node:stream'\nimport zlib from 'node:zlib'\n\nimport {type SanityDocument} from '@sanity/types'\nimport tar from 'tar-stream'\n\nimport {isTar} from './isTar.js'\n\nconst HEADER_SIZE = 300\n\n// https://github.com/kevva/is-gzip/blob/13dab7c877787bd5cff9de5482b1736f00df99c6/index.js\nconst isGzip = (buf: Buffer) =>\n buf.length >= 3 && buf[0] === 0x1f && buf[1] === 0x8b && buf[2] === 0x08\n\n// https://github.com/watson/is-deflate/blob/f9e8f0c7814eed715e13e29e97c69acee319686a/index.js\nconst isDeflate = (buf: Buffer) =>\n buf.length >= 2 && buf[0] === 0x78 && (buf[1] === 1 || buf[1] === 0x9c || buf[1] === 0xda)\n\nasync function* extract<TReturn>(\n stream: AsyncIterable<Buffer>,\n extractor: AsyncIterable<TReturn> & {\n destroy(): unknown\n end(data: void): unknown\n write(chunk: Buffer): unknown\n },\n) {\n // set up a task to drain the input iterable into the extractor asynchronously\n // before this function delegates to the extractor's iterable (containing the\n // result of the extraction)\n const drained = new Promise<void>((resolve, reject) => {\n // setTimeout is used here to ensure draining occurs after delegation\n setTimeout(async () => {\n try {\n for await (const chunk of stream) extractor.write(chunk)\n extractor.end()\n resolve()\n } catch (err) {\n reject(err)\n }\n })\n })\n\n // have this function delegate the results of the extractor\n yield* extractor\n await drained\n extractor.destroy()\n}\n\n/**\n * Given a async iterable of buffers, looks at the header of the file in the\n * first few bytes to see the file type then extracts the contents tries again.\n * If the given iterable of buffers is a tarball then it looks for an ndjson\n * files and returns another iterable of buffers with the contents of the\n * ndjson file\n */\nasync function* maybeExtractNdjson(stream: AsyncIterable<Buffer>): AsyncIterable<Buffer> {\n let buffer = Buffer.alloc(0)\n\n for await (const chunk of stream) {\n buffer = Buffer.concat([buffer, chunk])\n if (buffer.length < HEADER_SIZE) continue\n\n const fileHeader = buffer\n const restOfStream = async function* restOfStream() {\n yield fileHeader\n yield* stream\n }\n\n if (isGzip(fileHeader)) {\n yield* maybeExtractNdjson(extract(restOfStream(), zlib.createGunzip()))\n return\n }\n\n if (isDeflate(fileHeader)) {\n yield* maybeExtractNdjson(extract(restOfStream(), zlib.createDeflate()))\n return\n }\n\n if (isTar(fileHeader)) {\n for await (const entry of extract(restOfStream(), tar.extract())) {\n const filename = path.basename(entry.header.name)\n const extname = path.extname(filename).toLowerCase()\n // ignore hidden and non-ndjson files\n if (extname !== '.ndjson' || filename.startsWith('.')) continue\n\n for await (const ndjsonChunk of entry) yield ndjsonChunk as Buffer\n return\n }\n }\n\n yield* restOfStream()\n }\n}\n\n/**\n * Takes in an async iterable of buffers from an ndjson file or tarball and\n * returns an async iterable of sanity documents.\n */\nexport async function* extractDocumentsFromNdjsonOrTarball(\n file: AsyncIterable<Buffer>,\n): AsyncIterable<SanityDocument> {\n const lines = readline.createInterface({\n input: Readable.from(maybeExtractNdjson(file)),\n })\n\n for await (const line of lines) {\n const trimmed = line.trim()\n if (trimmed) yield JSON.parse(trimmed) as SanityDocument\n }\n lines.close()\n}\n"],"names":["path","readline","Readable","zlib","tar","isTar","HEADER_SIZE","isGzip","buf","length","isDeflate","extract","stream","extractor","drained","Promise","resolve","reject","setTimeout","chunk","write","end","err","destroy","maybeExtractNdjson","buffer","Buffer","alloc","concat","fileHeader","restOfStream","createGunzip","createDeflate","entry","filename","basename","header","name","extname","toLowerCase","startsWith","ndjsonChunk","extractDocumentsFromNdjsonOrTarball","file","lines","createInterface","input","from","line","trimmed","trim","JSON","parse","close"],"mappings":"AAAA,OAAOA,UAAU,YAAW;AAC5B,OAAOC,cAAc,gBAAe;AACpC,SAAQC,QAAQ,QAAO,cAAa;AACpC,OAAOC,UAAU,YAAW;AAG5B,OAAOC,SAAS,aAAY;AAE5B,SAAQC,KAAK,QAAO,aAAY;AAEhC,MAAMC,cAAc;AAEpB,0FAA0F;AAC1F,MAAMC,SAAS,CAACC,MACdA,IAAIC,MAAM,IAAI,KAAKD,GAAG,CAAC,EAAE,KAAK,QAAQA,GAAG,CAAC,EAAE,KAAK,QAAQA,GAAG,CAAC,EAAE,KAAK;AAEtE,8FAA8F;AAC9F,MAAME,YAAY,CAACF,MACjBA,IAAIC,MAAM,IAAI,KAAKD,GAAG,CAAC,EAAE,KAAK,QAASA,CAAAA,GAAG,CAAC,EAAE,KAAK,KAAKA,GAAG,CAAC,EAAE,KAAK,QAAQA,GAAG,CAAC,EAAE,KAAK,IAAG;AAE1F,gBAAgBG,QACdC,MAA6B,EAC7BC,SAIC;IAED,8EAA8E;IAC9E,6EAA6E;IAC7E,4BAA4B;IAC5B,MAAMC,UAAU,IAAIC,QAAc,CAACC,SAASC;QAC1C,qEAAqE;QACrEC,WAAW;YACT,IAAI;gBACF,WAAW,MAAMC,SAASP,OAAQC,UAAUO,KAAK,CAACD;gBAClDN,UAAUQ,GAAG;gBACbL;YACF,EAAE,OAAOM,KAAK;gBACZL,OAAOK;YACT;QACF;IACF;IAEA,2DAA2D;IAC3D,OAAOT;IACP,MAAMC;IACND,UAAUU,OAAO;AACnB;AAEA;;;;;;CAMC,GACD,gBAAgBC,mBAAmBZ,MAA6B;IAC9D,IAAIa,SAASC,OAAOC,KAAK,CAAC;IAE1B,WAAW,MAAMR,SAASP,OAAQ;QAChCa,SAASC,OAAOE,MAAM,CAAC;YAACH;YAAQN;SAAM;QACtC,IAAIM,OAAOhB,MAAM,GAAGH,aAAa;QAEjC,MAAMuB,aAAaJ;QACnB,MAAMK,eAAe,gBAAgBA;YACnC,MAAMD;YACN,OAAOjB;QACT;QAEA,IAAIL,OAAOsB,aAAa;YACtB,OAAOL,mBAAmBb,QAAQmB,gBAAgB3B,KAAK4B,YAAY;YACnE;QACF;QAEA,IAAIrB,UAAUmB,aAAa;YACzB,OAAOL,mBAAmBb,QAAQmB,gBAAgB3B,KAAK6B,aAAa;YACpE;QACF;QAEA,IAAI3B,MAAMwB,aAAa;YACrB,WAAW,MAAMI,SAAStB,QAAQmB,gBAAgB1B,IAAIO,OAAO,IAAK;gBAChE,MAAMuB,WAAWlC,KAAKmC,QAAQ,CAACF,MAAMG,MAAM,CAACC,IAAI;gBAChD,MAAMC,UAAUtC,KAAKsC,OAAO,CAACJ,UAAUK,WAAW;gBAClD,qCAAqC;gBACrC,IAAID,YAAY,aAAaJ,SAASM,UAAU,CAAC,MAAM;gBAEvD,WAAW,MAAMC,eAAeR,MAAO,MAAMQ;gBAC7C;YACF;QACF;QAEA,OAAOX;IACT;AACF;AAEA;;;CAGC,GACD,OAAO,gBAAgBY,oCACrBC,IAA2B;IAE3B,MAAMC,QAAQ3C,SAAS4C,eAAe,CAAC;QACrCC,OAAO5C,SAAS6C,IAAI,CAACvB,mBAAmBmB;IAC1C;IAEA,WAAW,MAAMK,QAAQJ,MAAO;QAC9B,MAAMK,UAAUD,KAAKE,IAAI;QACzB,IAAID,SAAS,MAAME,KAAKC,KAAK,CAACH;IAChC;IACAL,MAAMS,KAAK;AACb"}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.7.0",
|
|
4
4
|
"description": "Sanity CLI tool for managing Sanity projects and organizations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -65,19 +65,19 @@
|
|
|
65
65
|
"@sanity/client": "^8.4.0",
|
|
66
66
|
"@sanity/codegen": "^8.0.0",
|
|
67
67
|
"@sanity/descriptors": "^1.3.0",
|
|
68
|
-
"@sanity/export": "^6.2.
|
|
68
|
+
"@sanity/export": "^6.2.1",
|
|
69
69
|
"@sanity/generate-help-url": "^4.0.0",
|
|
70
70
|
"@sanity/id-utils": "^1.0.0",
|
|
71
71
|
"@sanity/import": "^6.0.4",
|
|
72
72
|
"@sanity/migrate": "^8.0.2",
|
|
73
|
-
"@sanity/runtime-cli": "^17.
|
|
74
|
-
"@sanity/schema": "^6.
|
|
73
|
+
"@sanity/runtime-cli": "^17.11.0",
|
|
74
|
+
"@sanity/schema": "^6.11.0",
|
|
75
75
|
"@sanity/telemetry": "^1.1.0",
|
|
76
76
|
"@sanity/template-validator": "^3.1.0",
|
|
77
|
-
"@sanity/types": "^6.
|
|
77
|
+
"@sanity/types": "^6.11.0",
|
|
78
78
|
"@sanity/worker-channels": "^2.0.0",
|
|
79
|
-
"@sanity/workflow-cli": "0.
|
|
80
|
-
"@sanity/workflow-engine": "0.
|
|
79
|
+
"@sanity/workflow-cli": "0.31.0",
|
|
80
|
+
"@sanity/workflow-engine": "0.31.0",
|
|
81
81
|
"@vercel/frameworks": "3.29.0",
|
|
82
82
|
"chokidar": "^5.0.0",
|
|
83
83
|
"console-table-printer": "^2.15.0",
|
|
@@ -120,10 +120,10 @@
|
|
|
120
120
|
"which": "^6.0.1",
|
|
121
121
|
"wrap-ansi": "^9.0.2",
|
|
122
122
|
"yaml": "^2.9.0",
|
|
123
|
-
"zod": "^4.
|
|
124
|
-
"@sanity/cli-build": "^6.
|
|
125
|
-
"@sanity/cli
|
|
126
|
-
"@sanity/
|
|
123
|
+
"zod": "^4.5.2",
|
|
124
|
+
"@sanity/cli-build": "^6.2.0",
|
|
125
|
+
"@sanity/workbench-cli": "^2.3.0",
|
|
126
|
+
"@sanity/cli-core": "^3.6.0"
|
|
127
127
|
},
|
|
128
128
|
"devDependencies": {
|
|
129
129
|
"@eslint/compat": "^2.1.0",
|
|
@@ -152,12 +152,12 @@
|
|
|
152
152
|
"oxc-transform-react": "^0.147.0",
|
|
153
153
|
"publint": "^0.3.21",
|
|
154
154
|
"rimraf": "^6.0.1",
|
|
155
|
-
"sanity": "^6.
|
|
155
|
+
"sanity": "^6.11.0",
|
|
156
156
|
"typescript": "^6.0.3",
|
|
157
157
|
"vitest": "^4.1.11",
|
|
158
|
-
"@repo/tsconfig": "3.70.0",
|
|
159
158
|
"@repo/package.config": "0.0.1",
|
|
160
|
-
"@
|
|
159
|
+
"@repo/tsconfig": "3.70.0",
|
|
160
|
+
"@sanity/cli-test": "16.0.0",
|
|
161
161
|
"@sanity/eslint-config-cli": "1.1.3"
|
|
162
162
|
},
|
|
163
163
|
"peerDependencies": {
|
package/dist/util/dates.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { pluralize } from './pluralize.js';
|
|
2
|
-
const MS_IN = {
|
|
3
|
-
day: 86_400_000,
|
|
4
|
-
hour: 3_600_000,
|
|
5
|
-
minute: 60_000,
|
|
6
|
-
month: 2_592_000_000,
|
|
7
|
-
second: 1000,
|
|
8
|
-
week: 604_800_000,
|
|
9
|
-
year: 31_536_000_000
|
|
10
|
-
};
|
|
11
|
-
/** Largest unit first, so the first unit the duration fills is the one we report. */ const UNITS = [
|
|
12
|
-
{
|
|
13
|
-
ms: MS_IN.year,
|
|
14
|
-
unit: 'year'
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
ms: MS_IN.month,
|
|
18
|
-
unit: 'month'
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
ms: MS_IN.week,
|
|
22
|
-
unit: 'week'
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
ms: MS_IN.day,
|
|
26
|
-
unit: 'day'
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
ms: MS_IN.hour,
|
|
30
|
-
unit: 'hour'
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
ms: MS_IN.minute,
|
|
34
|
-
unit: 'minute'
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
ms: MS_IN.second,
|
|
38
|
-
unit: 'second'
|
|
39
|
-
}
|
|
40
|
-
];
|
|
41
|
-
const relativeTime = new Intl.RelativeTimeFormat('en', {
|
|
42
|
-
numeric: 'always'
|
|
43
|
-
});
|
|
44
|
-
const DATE_ONLY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
45
|
-
function pad(value, length = 2) {
|
|
46
|
-
return String(value).padStart(length, '0');
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Returns the coarsest unit the elapsed time fills and the rounded number of those
|
|
50
|
-
* units, or `undefined` below a second.
|
|
51
|
-
*
|
|
52
|
-
* Rounding can land the value on the boundary of the next unit up, so we promote
|
|
53
|
-
* rather than report `60 minutes` where `1 hour` is meant. Units aren't all whole
|
|
54
|
-
* multiples of each other, so the boundary is the rounded count we'd display, which
|
|
55
|
-
* is why 25+ days reads as `1 month` rather than `4 weeks`.
|
|
56
|
-
*/ function selectUnit(elapsed) {
|
|
57
|
-
let index = UNITS.findIndex(({ ms })=>elapsed >= ms);
|
|
58
|
-
if (index === -1) return undefined;
|
|
59
|
-
while(index > 0 && Math.round(elapsed / UNITS[index].ms) >= Math.round(UNITS[index - 1].ms / UNITS[index].ms)){
|
|
60
|
-
index -= 1;
|
|
61
|
-
}
|
|
62
|
-
const { ms, unit } = UNITS[index];
|
|
63
|
-
return {
|
|
64
|
-
unit,
|
|
65
|
-
value: Math.round(elapsed / ms)
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Formats a timestamp as `YYYY-MM-DD HH:mm:ss` in the local time zone. Unparseable
|
|
70
|
-
* timestamps are returned as-is, so a bad value from the API doesn't fail the command.
|
|
71
|
-
*
|
|
72
|
-
* @param timestamp - An ISO 8601 timestamp
|
|
73
|
-
* @internal
|
|
74
|
-
*/ export function formatDateTime(timestamp) {
|
|
75
|
-
const date = new Date(timestamp);
|
|
76
|
-
if (!Number.isFinite(date.getTime())) return timestamp;
|
|
77
|
-
const day = `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
78
|
-
const time = `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
|
|
79
|
-
return `${day} ${time}`;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Formats a duration in milliseconds as an approximate, human readable length of
|
|
83
|
-
* time, eg `less than a minute`, `5 minutes` or `2 days`.
|
|
84
|
-
*
|
|
85
|
-
* @param ms - The duration in milliseconds
|
|
86
|
-
* @internal
|
|
87
|
-
*/ export function formatDuration(ms) {
|
|
88
|
-
if (!Number.isFinite(ms)) return '';
|
|
89
|
-
const selected = selectUnit(Math.abs(ms));
|
|
90
|
-
if (!selected || selected.unit === 'second') return 'less than a minute';
|
|
91
|
-
return `${selected.value} ${pluralize(selected.unit, selected.value)}`;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Formats a date relative to now, eg `2 days ago` or `in 3 hours`.
|
|
95
|
-
*
|
|
96
|
-
* @param date - The date to describe
|
|
97
|
-
* @param now - The reference point to compare against, defaults to the current time
|
|
98
|
-
* @internal
|
|
99
|
-
*/ export function formatTimeAgo(date, now = Date.now()) {
|
|
100
|
-
const delta = date.getTime() - now;
|
|
101
|
-
if (!Number.isFinite(delta)) return '';
|
|
102
|
-
const selected = selectUnit(Math.abs(delta));
|
|
103
|
-
if (!selected) return 'just now';
|
|
104
|
-
return relativeTime.format(delta < 0 ? -selected.value : selected.value, selected.unit);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Parses a `YYYY-MM-DD` date into a `Date` at local midnight. Returns `undefined`
|
|
108
|
-
* for anything that isn't a real calendar date in that exact format.
|
|
109
|
-
*
|
|
110
|
-
* @param value - The date string to parse
|
|
111
|
-
* @internal
|
|
112
|
-
*/ export function parseDateOnly(value) {
|
|
113
|
-
const match = DATE_ONLY_PATTERN.exec(value);
|
|
114
|
-
if (!match) return undefined;
|
|
115
|
-
const year = Number(match[1]);
|
|
116
|
-
const month = Number(match[2]);
|
|
117
|
-
const day = Number(match[3]);
|
|
118
|
-
const date = new Date(year, month - 1, day);
|
|
119
|
-
// `new Date(2024, 1, 31)` silently rolls over into March, so reject anything
|
|
120
|
-
// that didn't survive the round trip
|
|
121
|
-
const isRoundTrip = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
|
|
122
|
-
return isRoundTrip ? date : undefined;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
//# sourceMappingURL=dates.js.map
|
package/dist/util/dates.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/dates.ts"],"sourcesContent":["import {pluralize} from './pluralize.js'\n\nconst MS_IN = {\n day: 86_400_000,\n hour: 3_600_000,\n minute: 60_000,\n month: 2_592_000_000, // 30 days\n second: 1000,\n week: 604_800_000,\n year: 31_536_000_000, // 365 days\n} as const\n\n/** Largest unit first, so the first unit the duration fills is the one we report. */\nconst UNITS: {ms: number; unit: Intl.RelativeTimeFormatUnit}[] = [\n {ms: MS_IN.year, unit: 'year'},\n {ms: MS_IN.month, unit: 'month'},\n {ms: MS_IN.week, unit: 'week'},\n {ms: MS_IN.day, unit: 'day'},\n {ms: MS_IN.hour, unit: 'hour'},\n {ms: MS_IN.minute, unit: 'minute'},\n {ms: MS_IN.second, unit: 'second'},\n]\n\nconst relativeTime = new Intl.RelativeTimeFormat('en', {numeric: 'always'})\n\nconst DATE_ONLY_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/\n\nfunction pad(value: number, length = 2): string {\n return String(value).padStart(length, '0')\n}\n\n/**\n * Returns the coarsest unit the elapsed time fills and the rounded number of those\n * units, or `undefined` below a second.\n *\n * Rounding can land the value on the boundary of the next unit up, so we promote\n * rather than report `60 minutes` where `1 hour` is meant. Units aren't all whole\n * multiples of each other, so the boundary is the rounded count we'd display, which\n * is why 25+ days reads as `1 month` rather than `4 weeks`.\n */\nfunction selectUnit(\n elapsed: number,\n): {unit: Intl.RelativeTimeFormatUnit; value: number} | undefined {\n let index = UNITS.findIndex(({ms}) => elapsed >= ms)\n if (index === -1) return undefined\n\n while (\n index > 0 &&\n Math.round(elapsed / UNITS[index].ms) >= Math.round(UNITS[index - 1].ms / UNITS[index].ms)\n ) {\n index -= 1\n }\n\n const {ms, unit} = UNITS[index]\n return {unit, value: Math.round(elapsed / ms)}\n}\n\n/**\n * Formats a timestamp as `YYYY-MM-DD HH:mm:ss` in the local time zone. Unparseable\n * timestamps are returned as-is, so a bad value from the API doesn't fail the command.\n *\n * @param timestamp - An ISO 8601 timestamp\n * @internal\n */\nexport function formatDateTime(timestamp: string): string {\n const date = new Date(timestamp)\n if (!Number.isFinite(date.getTime())) return timestamp\n\n const day = `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`\n const time = `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`\n return `${day} ${time}`\n}\n\n/**\n * Formats a duration in milliseconds as an approximate, human readable length of\n * time, eg `less than a minute`, `5 minutes` or `2 days`.\n *\n * @param ms - The duration in milliseconds\n * @internal\n */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms)) return ''\n\n const selected = selectUnit(Math.abs(ms))\n if (!selected || selected.unit === 'second') return 'less than a minute'\n\n return `${selected.value} ${pluralize(selected.unit, selected.value)}`\n}\n\n/**\n * Formats a date relative to now, eg `2 days ago` or `in 3 hours`.\n *\n * @param date - The date to describe\n * @param now - The reference point to compare against, defaults to the current time\n * @internal\n */\nexport function formatTimeAgo(date: Date, now: number = Date.now()): string {\n const delta = date.getTime() - now\n if (!Number.isFinite(delta)) return ''\n\n const selected = selectUnit(Math.abs(delta))\n if (!selected) return 'just now'\n\n return relativeTime.format(delta < 0 ? -selected.value : selected.value, selected.unit)\n}\n\n/**\n * Parses a `YYYY-MM-DD` date into a `Date` at local midnight. Returns `undefined`\n * for anything that isn't a real calendar date in that exact format.\n *\n * @param value - The date string to parse\n * @internal\n */\nexport function parseDateOnly(value: string): Date | undefined {\n const match = DATE_ONLY_PATTERN.exec(value)\n if (!match) return undefined\n\n const year = Number(match[1])\n const month = Number(match[2])\n const day = Number(match[3])\n const date = new Date(year, month - 1, day)\n\n // `new Date(2024, 1, 31)` silently rolls over into March, so reject anything\n // that didn't survive the round trip\n const isRoundTrip =\n date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day\n\n return isRoundTrip ? date : undefined\n}\n"],"names":["pluralize","MS_IN","day","hour","minute","month","second","week","year","UNITS","ms","unit","relativeTime","Intl","RelativeTimeFormat","numeric","DATE_ONLY_PATTERN","pad","value","length","String","padStart","selectUnit","elapsed","index","findIndex","undefined","Math","round","formatDateTime","timestamp","date","Date","Number","isFinite","getTime","getFullYear","getMonth","getDate","time","getHours","getMinutes","getSeconds","formatDuration","selected","abs","formatTimeAgo","now","delta","format","parseDateOnly","match","exec","isRoundTrip"],"mappings":"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"}
|