@liiift-studio/deploy-vercel-from-sanity 1.1.0 → 1.2.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 +33 -19
- package/dist/index.d.mts +39 -9
- package/dist/index.d.ts +39 -9
- package/dist/index.js +768 -413
- package/dist/index.mjs +756 -445
- package/package.json +13 -7
- package/src/compat/code.tsx +29 -0
- package/src/compat/index.ts +14 -0
- package/src/compat/menu.tsx +225 -0
- package/src/compat/primitives.tsx +93 -0
- package/src/compat/resolve.ts +55 -0
- package/src/compat/toast.tsx +173 -0
- package/src/compat/tooltip.tsx +78 -0
- package/src/components/DeployHistory.tsx +19 -17
- package/src/components/DeployItem.tsx +38 -13
- package/src/components/DeployTargetForm.tsx +42 -16
- package/src/components/DeployTool.tsx +30 -8
- package/src/components/StatusBadge.tsx +1 -1
- package/src/components/TokenSetup.tsx +7 -7
- package/src/icons.tsx +31 -24
- package/src/index.ts +8 -3
- package/src/lib/api.ts +10 -4
- package/src/lib/helpers.ts +17 -0
- package/src/schema/schemaIcon.tsx +38 -0
- package/src/schema/vercelConfig.ts +34 -0
- package/src/schema/vercelDeploy.ts +2 -2
- package/src/version.ts +1 -1
- package/src/ui.tsx +0 -337
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Trigger and monitor Vercel deployments directly from [Sanity Studio](https://www.sanity.io) — no context switching required.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@liiift-studio/deploy-vercel-from-sanity)
|
|
6
|
-
[](https://www.sanity.io)
|
|
6
|
+
[](https://www.sanity.io)
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
|
|
9
9
|

|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
- **Deployment history** per target
|
|
24
24
|
- **"Open in Vercel"** link to your project dashboard
|
|
25
25
|
- **Multiple targets** — configure Production, Preview, and any number of custom environments
|
|
26
|
-
- **Shared API token** — set it once;
|
|
27
|
-
- **Responsive grid layout** —
|
|
26
|
+
- **Shared API token** — set it once; readable by anyone who can read the dataset (see [Security](#security))
|
|
27
|
+
- **Responsive grid layout** — cards reflow to fill the available width, one column on narrow viewports
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
@@ -97,7 +97,7 @@ EOF
|
|
|
97
97
|
|---|---|---|---|
|
|
98
98
|
| `name` | `string` | `'vercel-deploy'` | Tool slug in the Studio sidebar |
|
|
99
99
|
| `title` | `string` | `'Deploy'` | Tool label in the Studio sidebar |
|
|
100
|
-
| `icon` | `ComponentType` | `RocketIcon` |
|
|
100
|
+
| `icon` | `ComponentType` | `RocketIcon` | Accepted and stored on the tool descriptor. Note that no Studio version from v3 to v6 currently renders `tool.icon`, so this has no visible effect today. |
|
|
101
101
|
|
|
102
102
|
---
|
|
103
103
|
|
|
@@ -105,6 +105,8 @@ EOF
|
|
|
105
105
|
|
|
106
106
|
By default the Deploy tab is visible to all authenticated users. To hide it from viewers:
|
|
107
107
|
|
|
108
|
+
> Filter on the tool name you actually configured. The snippet below uses the default `vercel-deploy`; if you passed a custom `name`, match that instead or the filter silently does nothing.
|
|
109
|
+
|
|
108
110
|
```ts
|
|
109
111
|
// sanity.config.ts
|
|
110
112
|
tools: (prev, { currentUser }) => {
|
|
@@ -154,19 +156,19 @@ flowchart LR
|
|
|
154
156
|
|
|
155
157
|
## Troubleshooting
|
|
156
158
|
|
|
157
|
-
### "
|
|
159
|
+
### "Vercel API 401 — token is invalid or expired"
|
|
158
160
|
|
|
159
161
|
Your Vercel API token has been revoked or expired. Go to **Vercel → Settings → Tokens**, create a new token with **Full Account** scope, and reconnect it in the Deploy tab (top-right → *Token connected* button).
|
|
160
162
|
|
|
161
|
-
### "
|
|
163
|
+
### "Vercel API 403 — token lacks the required permissions"
|
|
162
164
|
|
|
163
165
|
The token exists but was created with insufficient scope. Vercel tokens need **Full Account** scope to read deployments. Delete the token and create a new one with the correct scope.
|
|
164
166
|
|
|
165
|
-
### "
|
|
167
|
+
### "Vercel API 404 — resource not found. Check the deploy hook URL and team ID."
|
|
166
168
|
|
|
167
169
|
Either the deploy hook URL is incorrect, or the project belongs to a Vercel team and the **Team ID** field is missing from the deploy target. Find your Team ID at **Vercel → Settings → General → Team ID** (starts with `team_`) and add it to the deploy target via the edit menu.
|
|
168
170
|
|
|
169
|
-
### "
|
|
171
|
+
### "Vercel API 429 — rate limit reached"
|
|
170
172
|
|
|
171
173
|
The plugin is making too many API calls at once (common when many targets are all actively building). Wait a few seconds — polling will resume automatically.
|
|
172
174
|
|
|
@@ -186,11 +188,11 @@ If "No stderr or stdout was captured" appears, the build may have failed before
|
|
|
186
188
|
|
|
187
189
|
## Security
|
|
188
190
|
|
|
189
|
-
**API token storage** — The Vercel API token is stored in a `config.vercelDeploy` Sanity document, readable by
|
|
191
|
+
**API token storage** — The Vercel API token is stored in cleartext in a `config.vercelDeploy` document of type `vercelDeploy.config`. Sanity has no per-document access control at this tier, so **the token is readable by anyone who can read the dataset** — and if the dataset is public, which is the usual setup for a statically generated front-end, that includes unauthenticated requests to the public GROQ API. A `viewer`-role member who cannot write a single document can also read it. Note that a **Full Account** scoped token can read and write your entire Vercel account, so anyone with studio access can read a credential that grants broad Vercel access — treat the token accordingly. The document type is registered with the plugin, so it is visible in Structure and can be deleted from the Studio to revoke the stored token. Audit who has access to your Sanity project at sanity.io → Project → Members, and do not store a Full Account token in a public dataset. If your studio includes untrusted editors, consider a server-side proxy that holds the token and exposes only a scoped deploy endpoint.
|
|
190
192
|
|
|
191
193
|
**Deploy hook URL validation** — `triggerDeploy` validates that the hook URL matches `api.vercel.com/v1/integrations/deploy/` before making the request, preventing SSRF from a tampered document.
|
|
192
194
|
|
|
193
|
-
**External links** — All external links use `target="_blank" rel="noreferrer"` and
|
|
195
|
+
**External links** — All external links use `target="_blank" rel="noreferrer"` and every `href` is validated before rendering: `safeHref()` rejects any non-http(s) scheme, and deployment hostnames from the API go through `deploymentHref()`, which rejects anything that is not a bare host. Both block `javascript:` injection and host substitution from a compromised API response.
|
|
194
196
|
|
|
195
197
|
**GROQ queries** — All GROQ queries in this plugin are static strings — no user input is interpolated.
|
|
196
198
|
|
|
@@ -198,23 +200,35 @@ If "No stderr or stdout was captured" appears, the build may have failed before
|
|
|
198
200
|
|
|
199
201
|
## Requirements
|
|
200
202
|
|
|
201
|
-
- Sanity Studio v3
|
|
202
|
-
- React 18 or 19
|
|
203
|
+
- Sanity Studio v3.30 or newer, through v6
|
|
204
|
+
- React 18 or 19 (Studio v5 and v6 require React 19)
|
|
205
|
+
- Node 20.19+ or 22.12+
|
|
203
206
|
- A Vercel account with at least one project and a deploy hook configured
|
|
204
207
|
|
|
205
|
-
Zero runtime dependencies — `react`, `sanity`, `@sanity/ui` and `@sanity/icons` are peer dependencies provided by your Studio; the plugin ships nothing else.
|
|
208
|
+
Zero runtime dependencies — `react`, `react-dom`, `sanity`, `@sanity/ui` and `@sanity/icons` are peer dependencies provided by your Studio; the plugin ships nothing else.
|
|
209
|
+
|
|
210
|
+
> **Why v3.30 and not v3.0?** `sanity@3.0` pulls `@sanity/ui` v1, and this plugin needs v2 or newer. `@sanity/ui` reaches 2.x at `sanity@3.30.0`.
|
|
206
211
|
|
|
207
212
|
### Studio compatibility
|
|
208
213
|
|
|
209
214
|
A single build supports the whole range. `@sanity/icons` v5 and `@sanity/ui` v4
|
|
210
|
-
both moved components out of their barrel files, so the plugin resolves
|
|
211
|
-
|
|
215
|
+
both moved components out of their barrel files, so the plugin resolves every
|
|
216
|
+
`@sanity/ui` and `@sanity/icons` value from the installed package at runtime
|
|
217
|
+
rather than importing names that exist on only one major.
|
|
218
|
+
|
|
219
|
+
Behaviour depends on the resolved packages, not on the Studio version — a
|
|
220
|
+
lockfile that hoists a different major changes which row applies:
|
|
212
221
|
|
|
213
|
-
|
|
|
222
|
+
| `@sanity/ui` | `@sanity/icons` | Typical Studio | Behaviour |
|
|
214
223
|
| --- | --- | --- | --- |
|
|
215
|
-
|
|
|
216
|
-
|
|
|
217
|
-
|
|
|
224
|
+
| 2.x | 2.x / 3.x | v3.30 – v3.x | Fully Studio-native |
|
|
225
|
+
| 3.x | 3.x | v4 – v6.3 | Fully Studio-native |
|
|
226
|
+
| 3.x | 5.x | v6.4 – v6.9 | Icons resolved via `<Icon symbol>` |
|
|
227
|
+
| 4.x | 5.x | v6.10+ | Tooltips, overflow menu, log blocks and toasts use built-in equivalents, since `@sanity/ui` v4 serves those from subpaths that do not exist on earlier majors |
|
|
228
|
+
|
|
229
|
+
The built-in equivalents are functional rather than pixel-identical to Studio's
|
|
230
|
+
own: the overflow menu implements the WAI-ARIA menu button pattern locally, and
|
|
231
|
+
toasts render in a live region anchored to the bottom-right of the tool.
|
|
218
232
|
|
|
219
233
|
---
|
|
220
234
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as sanity from 'sanity';
|
|
2
|
-
import
|
|
2
|
+
import * as react from 'react';
|
|
3
3
|
|
|
4
4
|
type VercelDeployState = 'QUEUED' | 'INITIALIZING' | 'BUILDING' | 'READY' | 'ERROR' | 'CANCELED' | 'LOADING';
|
|
5
5
|
/** A vercel_deploy document stored in the Sanity dataset */
|
|
@@ -52,16 +52,11 @@ interface VercelDeployPluginConfig {
|
|
|
52
52
|
icon?: React.ComponentType;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
/** Props every Sanity icon accepts — it renders a plain sized SVG. */
|
|
56
|
-
type IconProps = SVGProps<SVGSVGElement>;
|
|
57
|
-
/** An icon component, whichever shape the installed @sanity/icons exposes it in. */
|
|
58
|
-
type IconComponent = ComponentType<IconProps>;
|
|
59
|
-
|
|
60
55
|
declare const vercelDeploySchema: {
|
|
61
56
|
name: "vercel_deploy";
|
|
62
57
|
title: string;
|
|
63
58
|
type: "document";
|
|
64
|
-
icon:
|
|
59
|
+
icon: react.ForwardRefExoticComponent<Omit<react.SVGProps<SVGSVGElement>, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
65
60
|
fields: (({
|
|
66
61
|
name: "name";
|
|
67
62
|
title: string;
|
|
@@ -95,7 +90,42 @@ declare const vercelDeploySchema: {
|
|
|
95
90
|
};
|
|
96
91
|
|
|
97
92
|
/**
|
|
98
|
-
*
|
|
93
|
+
* Registers the document the plugin stores its Vercel token in.
|
|
94
|
+
*
|
|
95
|
+
* The document was previously written without a registered type, which made it
|
|
96
|
+
* invisible to Structure, absent from schema extraction, and impossible to
|
|
97
|
+
* inspect or revoke from inside the Studio. Registering it does not change where
|
|
98
|
+
* the token lives — see the security note in the README about dataset read
|
|
99
|
+
* access — but it does make the credential visible and removable.
|
|
100
|
+
*/
|
|
101
|
+
declare const vercelConfigSchema: {
|
|
102
|
+
name: "vercelDeploy.config";
|
|
103
|
+
title: string;
|
|
104
|
+
type: "document";
|
|
105
|
+
fields: {
|
|
106
|
+
name: "accessToken";
|
|
107
|
+
title: string;
|
|
108
|
+
type: "string";
|
|
109
|
+
description: string;
|
|
110
|
+
}[];
|
|
111
|
+
preview: {
|
|
112
|
+
select: {
|
|
113
|
+
token: string;
|
|
114
|
+
};
|
|
115
|
+
prepare: ({ token }: {
|
|
116
|
+
token?: string;
|
|
117
|
+
}) => {
|
|
118
|
+
title: string;
|
|
119
|
+
subtitle: string;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sanity Studio plugin — trigger and monitor Vercel deployments.
|
|
126
|
+
*
|
|
127
|
+
* Supports Studio v3.30 through v6 from a single build; see the compatibility
|
|
128
|
+
* table in the README for how @sanity/ui and @sanity/icons are resolved.
|
|
99
129
|
*
|
|
100
130
|
* @example
|
|
101
131
|
* // sanity.config.ts
|
|
@@ -111,4 +141,4 @@ declare const vercelDeploySchema: {
|
|
|
111
141
|
*/
|
|
112
142
|
declare const vercelDeploy: sanity.Plugin<void | VercelDeployPluginConfig>;
|
|
113
143
|
|
|
114
|
-
export { type DeployTarget, type VercelDeployPluginConfig, type VercelDeployState, type VercelDeployment, vercelDeploy, vercelDeploySchema };
|
|
144
|
+
export { type DeployTarget, type VercelDeployPluginConfig, type VercelDeployState, type VercelDeployment, vercelConfigSchema, vercelDeploy, vercelDeploySchema };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as sanity from 'sanity';
|
|
2
|
-
import
|
|
2
|
+
import * as react from 'react';
|
|
3
3
|
|
|
4
4
|
type VercelDeployState = 'QUEUED' | 'INITIALIZING' | 'BUILDING' | 'READY' | 'ERROR' | 'CANCELED' | 'LOADING';
|
|
5
5
|
/** A vercel_deploy document stored in the Sanity dataset */
|
|
@@ -52,16 +52,11 @@ interface VercelDeployPluginConfig {
|
|
|
52
52
|
icon?: React.ComponentType;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
/** Props every Sanity icon accepts — it renders a plain sized SVG. */
|
|
56
|
-
type IconProps = SVGProps<SVGSVGElement>;
|
|
57
|
-
/** An icon component, whichever shape the installed @sanity/icons exposes it in. */
|
|
58
|
-
type IconComponent = ComponentType<IconProps>;
|
|
59
|
-
|
|
60
55
|
declare const vercelDeploySchema: {
|
|
61
56
|
name: "vercel_deploy";
|
|
62
57
|
title: string;
|
|
63
58
|
type: "document";
|
|
64
|
-
icon:
|
|
59
|
+
icon: react.ForwardRefExoticComponent<Omit<react.SVGProps<SVGSVGElement>, "ref"> & react.RefAttributes<SVGSVGElement>>;
|
|
65
60
|
fields: (({
|
|
66
61
|
name: "name";
|
|
67
62
|
title: string;
|
|
@@ -95,7 +90,42 @@ declare const vercelDeploySchema: {
|
|
|
95
90
|
};
|
|
96
91
|
|
|
97
92
|
/**
|
|
98
|
-
*
|
|
93
|
+
* Registers the document the plugin stores its Vercel token in.
|
|
94
|
+
*
|
|
95
|
+
* The document was previously written without a registered type, which made it
|
|
96
|
+
* invisible to Structure, absent from schema extraction, and impossible to
|
|
97
|
+
* inspect or revoke from inside the Studio. Registering it does not change where
|
|
98
|
+
* the token lives — see the security note in the README about dataset read
|
|
99
|
+
* access — but it does make the credential visible and removable.
|
|
100
|
+
*/
|
|
101
|
+
declare const vercelConfigSchema: {
|
|
102
|
+
name: "vercelDeploy.config";
|
|
103
|
+
title: string;
|
|
104
|
+
type: "document";
|
|
105
|
+
fields: {
|
|
106
|
+
name: "accessToken";
|
|
107
|
+
title: string;
|
|
108
|
+
type: "string";
|
|
109
|
+
description: string;
|
|
110
|
+
}[];
|
|
111
|
+
preview: {
|
|
112
|
+
select: {
|
|
113
|
+
token: string;
|
|
114
|
+
};
|
|
115
|
+
prepare: ({ token }: {
|
|
116
|
+
token?: string;
|
|
117
|
+
}) => {
|
|
118
|
+
title: string;
|
|
119
|
+
subtitle: string;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sanity Studio plugin — trigger and monitor Vercel deployments.
|
|
126
|
+
*
|
|
127
|
+
* Supports Studio v3.30 through v6 from a single build; see the compatibility
|
|
128
|
+
* table in the README for how @sanity/ui and @sanity/icons are resolved.
|
|
99
129
|
*
|
|
100
130
|
* @example
|
|
101
131
|
* // sanity.config.ts
|
|
@@ -111,4 +141,4 @@ declare const vercelDeploySchema: {
|
|
|
111
141
|
*/
|
|
112
142
|
declare const vercelDeploy: sanity.Plugin<void | VercelDeployPluginConfig>;
|
|
113
143
|
|
|
114
|
-
export { type DeployTarget, type VercelDeployPluginConfig, type VercelDeployState, type VercelDeployment, vercelDeploy, vercelDeploySchema };
|
|
144
|
+
export { type DeployTarget, type VercelDeployPluginConfig, type VercelDeployState, type VercelDeployment, vercelConfigSchema, vercelDeploy, vercelDeploySchema };
|