@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 +139 -0
- package/dist/index.d.mts +75 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +768 -0
- package/dist/index.mjs +791 -0
- package/package.json +42 -0
- package/src/components/DeployHistory.tsx +157 -0
- package/src/components/DeployItem.tsx +298 -0
- package/src/components/DeployTool.tsx +184 -0
- package/src/components/StatusBadge.tsx +23 -0
- package/src/components/TokenSetup.tsx +92 -0
- package/src/index.ts +42 -0
- package/src/lib/api.ts +59 -0
- package/src/lib/helpers.ts +86 -0
- package/src/schema/vercelDeploy.ts +49 -0
- package/src/types.ts +63 -0
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
|
package/dist/index.d.mts
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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 };
|