@liiift-studio/deploy-vercel-from-sanity 0.1.1

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 ADDED
@@ -0,0 +1,139 @@
1
+ # deploy-vercel-from-sanity
2
+
3
+ Sanity Studio v5 plugin — trigger and monitor Vercel deployments directly from the Studio.
4
+
5
+ - Deploy button per target with live status polling
6
+ - Build timer while the deployment is running
7
+ - Branch, commit message, and creator shown inline
8
+ - Cancel an in-progress build
9
+ - Deployment history (last 10) with preview URLs and direct build log links
10
+ - Vercel API token stored securely in your Sanity dataset
11
+
12
+ ---
13
+
14
+ ## Requirements
15
+
16
+ - Sanity Studio v5
17
+ - A Vercel project with at least one [Deploy Hook](https://vercel.com/docs/git/deploy-hooks) configured
18
+ - A Vercel API token (for reading deployment status, history, and logs)
19
+
20
+ ---
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @liiift-studio/deploy-vercel-from-sanity
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Setup
31
+
32
+ ### 1. Add the plugin
33
+
34
+ ```ts
35
+ // sanity.config.ts
36
+ import { defineConfig } from 'sanity'
37
+ import { vercelDeploy } from '@liiift-studio/deploy-vercel-from-sanity'
38
+
39
+ export default defineConfig({
40
+ // ...
41
+ plugins: [
42
+ vercelDeploy(),
43
+ // or with custom label/icon:
44
+ vercelDeploy({ title: 'Deploy', name: 'vercel-deploy' }),
45
+ ],
46
+ })
47
+ ```
48
+
49
+ ### 2. Add a deploy hook document
50
+
51
+ Create a `vercel_deploy` document in your Sanity dataset with the deploy hook URL from
52
+ **Vercel → Project Settings → Git → Deploy Hooks**:
53
+
54
+ ```ts
55
+ // Via Sanity CLI (run once):
56
+ // npx sanity exec scripts/seed.js --with-user-token
57
+
58
+ import { getCliClient } from 'sanity/cli'
59
+ const client = getCliClient({ apiVersion: '2025-01-01' })
60
+
61
+ await client.createOrReplace({
62
+ _id: 'vercel-deploy-production',
63
+ _type: 'vercel_deploy',
64
+ name: 'Production',
65
+ url: 'https://api.vercel.com/v1/integrations/deploy/prj_xxx/yyy',
66
+ })
67
+ ```
68
+
69
+ Or create it from the Studio — the plugin registers the `vercel_deploy` schema automatically.
70
+
71
+ ### 3. Add your Vercel API token
72
+
73
+ On first launch, the plugin shows a token setup screen. Create a token at
74
+ **vercel.com → Settings → Tokens** with **Full Account** scope, paste it in, and save.
75
+
76
+ The token is stored in a Sanity document at `_id: "secrets.vercelDeploy"`.
77
+
78
+ ---
79
+
80
+ ## Security
81
+
82
+ ### Vercel API token storage
83
+
84
+ The token is stored in a Sanity document with `_id: "secrets.vercelDeploy"`. Sanity's
85
+ platform excludes documents in the `secrets.*` namespace from public/unauthenticated
86
+ API access — they are only readable by authenticated Studio sessions.
87
+
88
+ **If your dataset is in public mode**, verify this protection is in place before storing
89
+ sensitive credentials. You can confirm by attempting to fetch the document without an
90
+ auth token:
91
+
92
+ ```bash
93
+ curl "https://{projectId}.api.sanity.io/v2021-06-07/data/query/{dataset}?query=*[_id==\"secrets.vercelDeploy\"]"
94
+ # Should return empty results
95
+ ```
96
+
97
+ ### Link safety
98
+
99
+ All external links (`inspectorUrl`, preview URLs) from the Vercel API are validated
100
+ to allow only `http:` and `https:` protocols before being used as `href` values.
101
+ This prevents `javascript:` injection from a malformed API response.
102
+
103
+ ### Deploy hook URLs
104
+
105
+ Deploy hook URLs act as secrets — anyone with the URL can trigger a deployment.
106
+ Do not log them, commit them to public repos, or expose them client-side outside
107
+ the Studio. The plugin only sends a POST to the hook URL; the URL itself is never
108
+ displayed in full.
109
+
110
+ ---
111
+
112
+ ## `vercel_deploy` document schema
113
+
114
+ | Field | Type | Required | Description |
115
+ |---|---|---|---|
116
+ | `name` | string | ✓ | Display label (e.g. "Production") |
117
+ | `url` | url | ✓ | Vercel deploy hook URL |
118
+ | `teamId` | string | | Vercel team ID — required for team-owned projects |
119
+ | `disableDeleteAction` | boolean | | Prevent deletion from the Studio |
120
+
121
+ The `projectId` and hook ID are parsed automatically from the hook URL.
122
+
123
+ ---
124
+
125
+ ## Options
126
+
127
+ ```ts
128
+ vercelDeploy({
129
+ name?: string // Tool slug in the Studio sidebar (default: 'vercel-deploy')
130
+ title?: string // Tool label (default: 'Deploy')
131
+ icon?: React.ComponentType // Custom icon
132
+ })
133
+ ```
134
+
135
+ ---
136
+
137
+ ## License
138
+
139
+ MIT
@@ -0,0 +1,75 @@
1
+ import * as sanity from 'sanity';
2
+
3
+ type VercelDeployState = 'QUEUED' | 'INITIALIZING' | 'BUILDING' | 'READY' | 'ERROR' | 'CANCELED' | 'LOADING';
4
+ /** A vercel_deploy document stored in the Sanity dataset */
5
+ interface DeployTarget {
6
+ _id: string;
7
+ _type: 'vercel_deploy';
8
+ name: string;
9
+ /** Full Vercel deploy hook URL */
10
+ url: string;
11
+ /** Vercel team ID — optional, only needed for team projects */
12
+ teamId?: string;
13
+ /** Prevent editors from deleting this target */
14
+ disableDeleteAction?: boolean;
15
+ }
16
+ /** A single deployment returned by GET /v6/deployments */
17
+ interface VercelDeployment {
18
+ uid: string;
19
+ /** Preview hostname, e.g. my-project-abc123.vercel.app */
20
+ url: string;
21
+ state: VercelDeployState;
22
+ /** Unix ms timestamp */
23
+ created: number;
24
+ /** Link to the Vercel dashboard page for this deployment */
25
+ inspectorUrl?: string;
26
+ creator?: {
27
+ uid: string;
28
+ username: string;
29
+ avatar?: string;
30
+ };
31
+ meta?: {
32
+ githubCommitMessage?: string;
33
+ githubCommitRef?: string;
34
+ githubCommitSha?: string;
35
+ githubCommitAuthorName?: string;
36
+ };
37
+ }
38
+ /** Plugin configuration options */
39
+ interface VercelDeployPluginConfig {
40
+ /** Tool name slug shown in Studio sidebar (default: 'vercel-deploy') */
41
+ name?: string;
42
+ /** Tool label shown in Studio sidebar (default: 'Deploy') */
43
+ title?: string;
44
+ /** Custom icon component */
45
+ icon?: React.ComponentType;
46
+ }
47
+
48
+ declare const vercelDeploySchema: {
49
+ type: "document";
50
+ name: "vercel_deploy";
51
+ } & Omit<sanity.DocumentDefinition, "preview"> & {
52
+ preview?: sanity.PreviewConfig<{
53
+ title: string;
54
+ subtitle: string;
55
+ }, Record<"title" | "subtitle", any>> | undefined;
56
+ };
57
+
58
+ /**
59
+ * Sanity Studio v5 plugin — trigger and monitor Vercel deployments.
60
+ *
61
+ * @example
62
+ * // sanity.config.ts
63
+ * import { vercelDeploy } from 'deploy-vercel-from-sanity'
64
+ *
65
+ * export default defineConfig({
66
+ * plugins: [
67
+ * vercelDeploy(),
68
+ * // or with options:
69
+ * vercelDeploy({ title: 'Deploy', name: 'vercel-deploy' }),
70
+ * ],
71
+ * })
72
+ */
73
+ declare const vercelDeploy: sanity.Plugin<void | VercelDeployPluginConfig>;
74
+
75
+ export { type DeployTarget, type VercelDeployPluginConfig, type VercelDeployState, type VercelDeployment, vercelDeploy, vercelDeploySchema };
@@ -0,0 +1,75 @@
1
+ import * as sanity from 'sanity';
2
+
3
+ type VercelDeployState = 'QUEUED' | 'INITIALIZING' | 'BUILDING' | 'READY' | 'ERROR' | 'CANCELED' | 'LOADING';
4
+ /** A vercel_deploy document stored in the Sanity dataset */
5
+ interface DeployTarget {
6
+ _id: string;
7
+ _type: 'vercel_deploy';
8
+ name: string;
9
+ /** Full Vercel deploy hook URL */
10
+ url: string;
11
+ /** Vercel team ID — optional, only needed for team projects */
12
+ teamId?: string;
13
+ /** Prevent editors from deleting this target */
14
+ disableDeleteAction?: boolean;
15
+ }
16
+ /** A single deployment returned by GET /v6/deployments */
17
+ interface VercelDeployment {
18
+ uid: string;
19
+ /** Preview hostname, e.g. my-project-abc123.vercel.app */
20
+ url: string;
21
+ state: VercelDeployState;
22
+ /** Unix ms timestamp */
23
+ created: number;
24
+ /** Link to the Vercel dashboard page for this deployment */
25
+ inspectorUrl?: string;
26
+ creator?: {
27
+ uid: string;
28
+ username: string;
29
+ avatar?: string;
30
+ };
31
+ meta?: {
32
+ githubCommitMessage?: string;
33
+ githubCommitRef?: string;
34
+ githubCommitSha?: string;
35
+ githubCommitAuthorName?: string;
36
+ };
37
+ }
38
+ /** Plugin configuration options */
39
+ interface VercelDeployPluginConfig {
40
+ /** Tool name slug shown in Studio sidebar (default: 'vercel-deploy') */
41
+ name?: string;
42
+ /** Tool label shown in Studio sidebar (default: 'Deploy') */
43
+ title?: string;
44
+ /** Custom icon component */
45
+ icon?: React.ComponentType;
46
+ }
47
+
48
+ declare const vercelDeploySchema: {
49
+ type: "document";
50
+ name: "vercel_deploy";
51
+ } & Omit<sanity.DocumentDefinition, "preview"> & {
52
+ preview?: sanity.PreviewConfig<{
53
+ title: string;
54
+ subtitle: string;
55
+ }, Record<"title" | "subtitle", any>> | undefined;
56
+ };
57
+
58
+ /**
59
+ * Sanity Studio v5 plugin — trigger and monitor Vercel deployments.
60
+ *
61
+ * @example
62
+ * // sanity.config.ts
63
+ * import { vercelDeploy } from 'deploy-vercel-from-sanity'
64
+ *
65
+ * export default defineConfig({
66
+ * plugins: [
67
+ * vercelDeploy(),
68
+ * // or with options:
69
+ * vercelDeploy({ title: 'Deploy', name: 'vercel-deploy' }),
70
+ * ],
71
+ * })
72
+ */
73
+ declare const vercelDeploy: sanity.Plugin<void | VercelDeployPluginConfig>;
74
+
75
+ export { type DeployTarget, type VercelDeployPluginConfig, type VercelDeployState, type VercelDeployment, vercelDeploy, vercelDeploySchema };