@sanity/vercel-protection-bypass 1.0.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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +46 -0
- package/dist/_chunks-cjs/VercelProtectionBypassTool.cjs +188 -0
- package/dist/_chunks-cjs/VercelProtectionBypassTool.cjs.map +1 -0
- package/dist/_chunks-es/VercelProtectionBypassTool.js +196 -0
- package/dist/_chunks-es/VercelProtectionBypassTool.js.map +1 -0
- package/dist/index.cjs +26 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/package.json +78 -0
- package/src/VercelProtectionBypassTool.tsx +263 -0
- package/src/index.ts +29 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 (2025-01-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add Vercel Protection Bypass tool ([#2479](https://github.com/sanity-io/visual-editing/issues/2479)) ([7e58143](https://github.com/sanity-io/visual-editing/commit/7e58143e3f70751dbd424641045b218d7e9085b4))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @sanity/preview-url-secret bumped to 2.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Sanity
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @sanity/vercel-protection-bypass
|
|
2
|
+
|
|
3
|
+
[](https://npm-stat.com/charts.html?package=@sanity/vercel-protection-bypass)
|
|
4
|
+
[](https://www.npmjs.com/package/@sanity/vercel-protection-bypass)
|
|
5
|
+
[![gzip size][gzip-badge]][bundlephobia]
|
|
6
|
+
[![size][size-badge]][bundlephobia]
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm install @sanity/vercel-protection-bypass
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
This package is used together with [`sanity/presentation`] to configure it to work with Vercel's [Deployment Protection](https://vercel.com/docs/security/deployment-protection) feature.
|
|
13
|
+
The tool is only needed for setup, once it's configured you can safely uninstall it.
|
|
14
|
+
|
|
15
|
+
Add the tool your `sanity.config.ts`:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// ./sanity.config.ts
|
|
19
|
+
import {vercelProtectionBypassTool} from '@sanity/vercel-protection-bypass'
|
|
20
|
+
import {defineConfig} from 'sanity'
|
|
21
|
+
import {presentationTool} from 'sanity/presentation'
|
|
22
|
+
|
|
23
|
+
export default defineConfig({
|
|
24
|
+
// ... other options
|
|
25
|
+
plugins: [
|
|
26
|
+
// ... other plugins
|
|
27
|
+
presentationTool({
|
|
28
|
+
previewUrl: {
|
|
29
|
+
// @TODO change to the URL of the application, or `location.origin` if it's an embedded Studio
|
|
30
|
+
origin: 'http://localhost:3000',
|
|
31
|
+
previewMode: {
|
|
32
|
+
enable: '/api/draft',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
vercelProtectionBypassTool(),
|
|
37
|
+
],
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
You should see a new `Vercel Protection Bypass` tab in the Studio's settings. Click it and follow the instructions to set up the tool.
|
|
42
|
+
|
|
43
|
+
[`sanity/presentation`]: https://github.com/sanity-io/visual-editing/tree/main/packages/presentation#readme
|
|
44
|
+
[gzip-badge]: https://img.shields.io/bundlephobia/minzip/@sanity/vercel-protection-bypass?label=gzip%20size&style=flat-square
|
|
45
|
+
[size-badge]: https://img.shields.io/bundlephobia/min/@sanity/vercel-protection-bypass?label=size&style=flat-square
|
|
46
|
+
[bundlephobia]: https://bundlephobia.com/package/@sanity/vercel-protection-bypass
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var jsxRuntime = require("react/jsx-runtime"), reactCompilerRuntime = require("react-compiler-runtime"), icons = require("@sanity/icons"), constants = require("@sanity/preview-url-secret/constants"), toggleVercelProtectionBypass = require("@sanity/preview-url-secret/toggle-vercel-protection-bypass"), ui = require("@sanity/ui"), react = require("react"), sanity = require("sanity");
|
|
3
|
+
function reducer(prevState, action) {
|
|
4
|
+
switch (action.type) {
|
|
5
|
+
case "removed-secret":
|
|
6
|
+
return {
|
|
7
|
+
...prevState,
|
|
8
|
+
status: "disabled"
|
|
9
|
+
};
|
|
10
|
+
case "remove-secret":
|
|
11
|
+
return {
|
|
12
|
+
...prevState,
|
|
13
|
+
status: "removing-secret"
|
|
14
|
+
};
|
|
15
|
+
case "saved-secret":
|
|
16
|
+
return {
|
|
17
|
+
...prevState,
|
|
18
|
+
status: "enabled"
|
|
19
|
+
};
|
|
20
|
+
case "save-secret":
|
|
21
|
+
return {
|
|
22
|
+
...prevState,
|
|
23
|
+
status: "adding-secret"
|
|
24
|
+
};
|
|
25
|
+
case "cancel-add-secret":
|
|
26
|
+
return {
|
|
27
|
+
...prevState,
|
|
28
|
+
status: "disabled"
|
|
29
|
+
};
|
|
30
|
+
case "add-secret":
|
|
31
|
+
return {
|
|
32
|
+
...prevState,
|
|
33
|
+
status: "add-secret-dialog"
|
|
34
|
+
};
|
|
35
|
+
case "failed-remove-secret":
|
|
36
|
+
return {
|
|
37
|
+
...prevState,
|
|
38
|
+
status: "enabled"
|
|
39
|
+
};
|
|
40
|
+
case "failed-add-secret":
|
|
41
|
+
return {
|
|
42
|
+
...prevState,
|
|
43
|
+
status: "add-secret-dialog"
|
|
44
|
+
};
|
|
45
|
+
default:
|
|
46
|
+
return prevState;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function VercelProtectionBypassTool() {
|
|
50
|
+
const $ = reactCompilerRuntime.c(25);
|
|
51
|
+
let t0;
|
|
52
|
+
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
|
|
53
|
+
apiVersion: constants.apiVersion
|
|
54
|
+
}, $[0] = t0) : t0 = $[0];
|
|
55
|
+
const client = sanity.useClient(t0), {
|
|
56
|
+
push: pushToast
|
|
57
|
+
} = ui.useToast();
|
|
58
|
+
let t1;
|
|
59
|
+
$[1] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
|
|
60
|
+
status: "loading"
|
|
61
|
+
}, $[1] = t1) : t1 = $[1];
|
|
62
|
+
const [state, dispatch] = react.useReducer(reducer, t1), adding = state.status === "adding-secret", removing = state.status === "removing-secret";
|
|
63
|
+
let t2;
|
|
64
|
+
$[2] !== client || $[3] !== pushToast ? (t2 = (secret) => {
|
|
65
|
+
dispatch({
|
|
66
|
+
type: "save-secret"
|
|
67
|
+
}), toggleVercelProtectionBypass.enableVercelProtectionBypass(client, secret).then(() => {
|
|
68
|
+
dispatch({
|
|
69
|
+
type: "saved-secret"
|
|
70
|
+
}), pushToast({
|
|
71
|
+
status: "success",
|
|
72
|
+
title: "Protection bypass is now enabled"
|
|
73
|
+
});
|
|
74
|
+
}).catch((reason) => {
|
|
75
|
+
console.error(reason), pushToast({
|
|
76
|
+
status: "error",
|
|
77
|
+
title: "There was an error when trying to enable protection bypass. See the browser console for more information."
|
|
78
|
+
}), dispatch({
|
|
79
|
+
type: "failed-add-secret"
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}, $[2] = client, $[3] = pushToast, $[4] = t2) : t2 = $[4];
|
|
83
|
+
const handleEnable = t2;
|
|
84
|
+
let t3, t4;
|
|
85
|
+
$[5] !== client ? (t3 = () => {
|
|
86
|
+
const unsubscribe = toggleVercelProtectionBypass.subcribeToVercelProtectionBypass(client, (secret_0) => dispatch({
|
|
87
|
+
type: secret_0 ? "saved-secret" : "removed-secret"
|
|
88
|
+
}));
|
|
89
|
+
return () => unsubscribe();
|
|
90
|
+
}, t4 = [client], $[5] = client, $[6] = t3, $[7] = t4) : (t3 = $[6], t4 = $[7]), react.useEffect(t3, t4);
|
|
91
|
+
const enabled = state.status === "enabled" || removing;
|
|
92
|
+
let t5;
|
|
93
|
+
$[8] === Symbol.for("react.memo_cache_sentinel") ? (t5 = {
|
|
94
|
+
height: "100%",
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
justifyContent: "center",
|
|
97
|
+
flexDirection: "column"
|
|
98
|
+
}, $[8] = t5) : t5 = $[8];
|
|
99
|
+
let t6;
|
|
100
|
+
$[9] === Symbol.for("react.memo_cache_sentinel") ? (t6 = {
|
|
101
|
+
maxWidth: 640
|
|
102
|
+
}, $[9] = t6) : t6 = $[9];
|
|
103
|
+
let t7, t8;
|
|
104
|
+
$[10] === Symbol.for("react.memo_cache_sentinel") ? (t7 = {
|
|
105
|
+
justifyItems: "flex-start",
|
|
106
|
+
textWrap: "pretty"
|
|
107
|
+
}, t8 = /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Vercel Protection Bypass" }), $[10] = t7, $[11] = t8) : (t7 = $[10], t8 = $[11]);
|
|
108
|
+
let t9;
|
|
109
|
+
$[12] !== client || $[13] !== enabled || $[14] !== pushToast || $[15] !== removing || $[16] !== state.status ? (t9 = /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { sizing: "border", display: "flex", style: t5, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 5, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 4, style: t6, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 4, style: t7, children: [
|
|
110
|
+
t8,
|
|
111
|
+
enabled ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
112
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { style: {
|
|
113
|
+
textWrap: "pretty"
|
|
114
|
+
}, children: [
|
|
115
|
+
"Sanity Presentation is setup to use",
|
|
116
|
+
" ",
|
|
117
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { href: "https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation", target: "_blank", rel: "noreferrer", children: "protection bypass for automation" }),
|
|
118
|
+
" ",
|
|
119
|
+
"in order to display protected deployments in its preview iframe for the current Sanity dataset."
|
|
120
|
+
] }) }),
|
|
121
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "You can turn off automatic protection bypass at any time by clicking the button below." }) }),
|
|
122
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { mode: "ghost", tone: "critical", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.TrashIcon, {}), loading: removing, onClick: () => {
|
|
123
|
+
dispatch({
|
|
124
|
+
type: "remove-secret"
|
|
125
|
+
}), toggleVercelProtectionBypass.disableVercelProtectionBypass(client).then(() => {
|
|
126
|
+
pushToast({
|
|
127
|
+
status: "warning",
|
|
128
|
+
title: "Protection bypass is now disabled"
|
|
129
|
+
}), dispatch({
|
|
130
|
+
type: "removed-secret"
|
|
131
|
+
});
|
|
132
|
+
}).catch((reason_0) => {
|
|
133
|
+
console.error(reason_0), pushToast({
|
|
134
|
+
status: "error",
|
|
135
|
+
title: "There was an error when trying to disable protection bypass. See the browser console for more information."
|
|
136
|
+
}), dispatch({
|
|
137
|
+
type: "failed-remove-secret"
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}, text: "Remove secret" }),
|
|
141
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Protection bypass remains enabled if this plugin is removed from your Sanity config." })
|
|
142
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
143
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { style: {
|
|
144
|
+
textWrap: "pretty"
|
|
145
|
+
}, children: [
|
|
146
|
+
"Follow the instructions on",
|
|
147
|
+
" ",
|
|
148
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { href: "https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation", target: "_blank", rel: "noreferrer", children: "how to enable protection bypass for automation" }),
|
|
149
|
+
"."
|
|
150
|
+
] }) }),
|
|
151
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "This will setup a secret that Vercel exposes as an environment variable called VERCEL_AUTOMATION_BYPASS_SECRET, its value is the secret you need." }) }),
|
|
152
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { mode: "ghost", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.AddIcon, {}), loading: state.status === "loading", onClick: () => {
|
|
153
|
+
dispatch({
|
|
154
|
+
type: "add-secret"
|
|
155
|
+
});
|
|
156
|
+
}, text: "Add secret" }),
|
|
157
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "If you're using Sanity Presentation Tool with multiple protected deployments ensure that they have the same secret set, as this tool will set a secret that is shared in your dataset with all instances of Presentation Tool." })
|
|
158
|
+
] })
|
|
159
|
+
] }) }) }) }), $[12] = client, $[13] = enabled, $[14] = pushToast, $[15] = removing, $[16] = state.status, $[17] = t9) : t9 = $[17];
|
|
160
|
+
let t10;
|
|
161
|
+
$[18] !== adding || $[19] !== handleEnable || $[20] !== state.status ? (t10 = (state.status === "add-secret-dialog" || state.status === "adding-secret") && /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { animate: !0, id: "add-secret-dialog", onClickOutside: () => dispatch({
|
|
162
|
+
type: "cancel-add-secret"
|
|
163
|
+
}), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit: (event) => {
|
|
164
|
+
event.preventDefault(), event.currentTarget.reportValidity();
|
|
165
|
+
const secret_1 = new FormData(event.currentTarget).get("secret");
|
|
166
|
+
secret_1 && handleEnable(secret_1);
|
|
167
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
168
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
|
|
169
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "label", weight: "semibold", size: 1, children: "Add bypass secret" }),
|
|
170
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "Make sure it's the same secret the Vercel deployment is using that's loaded in the preview iframe." }),
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, { name: "secret", onFocus: _temp, onBlur: _temp2, minLength: 32, maxLength: 32, autoComplete: "off", autoCapitalize: "off", autoCorrect: "off", spellCheck: "false", disabled: adding })
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", loading: adding, text: adding ? "Saving\u2026" : "Save", tone: "positive" })
|
|
174
|
+
] }) }) }) }), $[18] = adding, $[19] = handleEnable, $[20] = state.status, $[21] = t10) : t10 = $[21];
|
|
175
|
+
let t11;
|
|
176
|
+
return $[22] !== t10 || $[23] !== t9 ? (t11 = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
177
|
+
t9,
|
|
178
|
+
t10
|
|
179
|
+
] }), $[22] = t10, $[23] = t9, $[24] = t11) : t11 = $[24], t11;
|
|
180
|
+
}
|
|
181
|
+
function _temp2(event_1) {
|
|
182
|
+
event_1.currentTarget.setCustomValidity(event_1.currentTarget.value.length == 32 ? "" : "Secret must be 32 characters long"), event_1.currentTarget.required = !0;
|
|
183
|
+
}
|
|
184
|
+
function _temp(event_0) {
|
|
185
|
+
event_0.currentTarget.setCustomValidity("");
|
|
186
|
+
}
|
|
187
|
+
exports.default = VercelProtectionBypassTool;
|
|
188
|
+
//# sourceMappingURL=VercelProtectionBypassTool.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VercelProtectionBypassTool.cjs","sources":["../../src/VercelProtectionBypassTool.tsx"],"sourcesContent":["import {AddIcon, TrashIcon} from '@sanity/icons'\nimport {apiVersion} from '@sanity/preview-url-secret/constants'\nimport {\n disableVercelProtectionBypass,\n enableVercelProtectionBypass,\n subcribeToVercelProtectionBypass,\n} from '@sanity/preview-url-secret/toggle-vercel-protection-bypass'\nimport {Box, Button, Card, Dialog, Heading, Stack, Text, TextInput, useToast} from '@sanity/ui'\nimport {useEffect, useReducer} from 'react'\nimport {useClient} from 'sanity'\n\ninterface State {\n status:\n | 'loading'\n | 'disabled'\n | 'add-secret-dialog'\n | 'adding-secret'\n | 'enabled'\n | 'removing-secret'\n}\ntype Action =\n | {type: 'add-secret'}\n | {type: 'save-secret'}\n | {type: 'cancel-add-secret'}\n | {type: 'failed-add-secret'}\n | {type: 'saved-secret'}\n | {type: 'remove-secret'}\n | {type: 'failed-remove-secret'}\n | {type: 'removed-secret'}\n\nfunction reducer(prevState: State, action: Action): State {\n switch (action.type) {\n case 'removed-secret':\n return {...prevState, status: 'disabled'}\n case 'remove-secret':\n return {...prevState, status: 'removing-secret'}\n case 'saved-secret':\n return {...prevState, status: 'enabled'}\n case 'save-secret':\n return {...prevState, status: 'adding-secret'}\n case 'cancel-add-secret':\n return {...prevState, status: 'disabled'}\n case 'add-secret':\n return {...prevState, status: 'add-secret-dialog'}\n case 'failed-remove-secret':\n return {...prevState, status: 'enabled'}\n case 'failed-add-secret':\n return {...prevState, status: 'add-secret-dialog'}\n default:\n return prevState\n }\n}\n\nexport default function VercelProtectionBypassTool(): React.JSX.Element {\n const client = useClient({apiVersion: apiVersion})\n const {push: pushToast} = useToast()\n const [state, dispatch] = useReducer(reducer, {status: 'loading'})\n const adding = state.status === 'adding-secret'\n const removing = state.status === 'removing-secret'\n\n const handleEnable = (secret: string) => {\n dispatch({type: 'save-secret'})\n enableVercelProtectionBypass(client, secret)\n .then(() => {\n dispatch({type: 'saved-secret'})\n pushToast({\n status: 'success',\n title: 'Protection bypass is now enabled',\n })\n })\n .catch((reason) => {\n // eslint-disable-next-line no-console\n console.error(reason)\n pushToast({\n status: 'error',\n title:\n 'There was an error when trying to enable protection bypass. See the browser console for more information.',\n })\n dispatch({type: 'failed-add-secret'})\n })\n }\n\n useEffect(() => {\n const unsubscribe = subcribeToVercelProtectionBypass(client, (secret) =>\n dispatch({type: secret ? 'saved-secret' : 'removed-secret'}),\n )\n return () => unsubscribe()\n }, [client])\n\n const enabled = state.status === 'enabled' || removing\n\n return (\n <>\n <Box\n sizing=\"border\"\n display=\"flex\"\n style={{\n height: '100%',\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n }}\n >\n <Stack space={5}>\n <Card padding={4} style={{maxWidth: 640}}>\n <Stack space={4} style={{justifyItems: 'flex-start', textWrap: 'pretty'}}>\n <Heading>Vercel Protection Bypass</Heading>\n {enabled ? (\n <>\n <Box>\n <Text style={{textWrap: 'pretty'}}>\n Sanity Presentation is setup to use{' '}\n <a\n href=\"https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n protection bypass for automation\n </a>{' '}\n in order to display protected deployments in its preview iframe for the\n current Sanity dataset.\n </Text>\n </Box>\n <Box>\n <Text>\n You can turn off automatic protection bypass at any time by clicking the\n button below.\n </Text>\n </Box>\n <Button\n mode=\"ghost\"\n tone=\"critical\"\n icon={<TrashIcon />}\n loading={removing}\n onClick={() => {\n dispatch({type: 'remove-secret'})\n disableVercelProtectionBypass(client)\n .then(() => {\n pushToast({\n status: 'warning',\n title: 'Protection bypass is now disabled',\n })\n dispatch({type: 'removed-secret'})\n })\n .catch((reason) => {\n // eslint-disable-next-line no-console\n console.error(reason)\n pushToast({\n status: 'error',\n title:\n 'There was an error when trying to disable protection bypass. See the browser console for more information.',\n })\n dispatch({type: 'failed-remove-secret'})\n })\n }}\n text=\"Remove secret\"\n />\n <Text>\n Protection bypass remains enabled if this plugin is removed from your Sanity\n config.\n </Text>\n </>\n ) : (\n <>\n <Box>\n <Text style={{textWrap: 'pretty'}}>\n Follow the instructions on{' '}\n <a\n href=\"https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n how to enable protection bypass for automation\n </a>\n .\n </Text>\n </Box>\n <Box>\n <Text>\n This will setup a secret that Vercel exposes as an environment variable called\n VERCEL_AUTOMATION_BYPASS_SECRET, its value is the secret you need.\n </Text>\n </Box>\n <Button\n mode=\"ghost\"\n icon={<AddIcon />}\n loading={state.status === 'loading'}\n onClick={() => {\n dispatch({type: 'add-secret'})\n }}\n text=\"Add secret\"\n />\n <Text>\n If you're using Sanity Presentation Tool with multiple protected\n deployments ensure that they have the same secret set, as this tool will set a\n secret that is shared in your dataset with all instances of Presentation Tool.\n </Text>\n </>\n )}\n </Stack>\n </Card>\n </Stack>\n </Box>\n {(state.status === 'add-secret-dialog' || state.status === 'adding-secret') && (\n <Dialog\n animate\n id=\"add-secret-dialog\"\n onClickOutside={() => dispatch({type: 'cancel-add-secret'})}\n >\n <Card padding={3}>\n <form\n onSubmit={(event) => {\n event.preventDefault()\n event.currentTarget.reportValidity()\n const formData = new FormData(event.currentTarget)\n const secret = formData.get('secret') as string\n if (secret) handleEnable(secret)\n }}\n >\n <Stack space={3}>\n <Stack space={2}>\n <Text as=\"label\" weight=\"semibold\" size={1}>\n Add bypass secret\n </Text>\n <Text muted size={1}>\n {`Make sure it's the same secret the Vercel deployment is using that's loaded in the preview iframe.`}\n </Text>\n <TextInput\n name=\"secret\"\n onFocus={(event) => {\n event.currentTarget.setCustomValidity('')\n }}\n onBlur={(event) => {\n event.currentTarget.setCustomValidity(\n event.currentTarget.value.length == 32\n ? ''\n : 'Secret must be 32 characters long',\n )\n event.currentTarget.required = true\n }}\n minLength={32}\n maxLength={32}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n spellCheck=\"false\"\n disabled={adding}\n />\n </Stack>\n <Button\n type=\"submit\"\n loading={adding}\n text={adding ? 'Saving…' : 'Save'}\n tone=\"positive\"\n />\n </Stack>\n </form>\n </Card>\n </Dialog>\n )}\n </>\n )\n}\n"],"names":["reducer","prevState","action","type","status","VercelProtectionBypassTool","$","_c","t0","Symbol","for","apiVersion","client","useClient","push","pushToast","useToast","t1","state","dispatch","useReducer","adding","removing","t2","secret","enableVercelProtectionBypass","then","title","catch","reason","error","handleEnable","t3","t4","unsubscribe","subcribeToVercelProtectionBypass","secret_0","useEffect","enabled","t5","height","alignItems","justifyContent","flexDirection","t6","maxWidth","t7","t8","justifyItems","textWrap","jsx","Heading","t9","Box","Stack","Card","jsxs","Fragment","Text","Button","TrashIcon","disableVercelProtectionBypass","reason_0","AddIcon","t10","Dialog","event","preventDefault","currentTarget","reportValidity","secret_1","FormData","get","TextInput","_temp","_temp2","t11","event_1","setCustomValidity","value","length","required","event_0"],"mappings":"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"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { c } from "react-compiler-runtime";
|
|
3
|
+
import { TrashIcon, AddIcon } from "@sanity/icons";
|
|
4
|
+
import { apiVersion } from "@sanity/preview-url-secret/constants";
|
|
5
|
+
import { enableVercelProtectionBypass, subcribeToVercelProtectionBypass, disableVercelProtectionBypass } from "@sanity/preview-url-secret/toggle-vercel-protection-bypass";
|
|
6
|
+
import { useToast, Heading, Box, Stack, Card, Text, Button, Dialog, TextInput } from "@sanity/ui";
|
|
7
|
+
import { useReducer, useEffect } from "react";
|
|
8
|
+
import { useClient } from "sanity";
|
|
9
|
+
function reducer(prevState, action) {
|
|
10
|
+
switch (action.type) {
|
|
11
|
+
case "removed-secret":
|
|
12
|
+
return {
|
|
13
|
+
...prevState,
|
|
14
|
+
status: "disabled"
|
|
15
|
+
};
|
|
16
|
+
case "remove-secret":
|
|
17
|
+
return {
|
|
18
|
+
...prevState,
|
|
19
|
+
status: "removing-secret"
|
|
20
|
+
};
|
|
21
|
+
case "saved-secret":
|
|
22
|
+
return {
|
|
23
|
+
...prevState,
|
|
24
|
+
status: "enabled"
|
|
25
|
+
};
|
|
26
|
+
case "save-secret":
|
|
27
|
+
return {
|
|
28
|
+
...prevState,
|
|
29
|
+
status: "adding-secret"
|
|
30
|
+
};
|
|
31
|
+
case "cancel-add-secret":
|
|
32
|
+
return {
|
|
33
|
+
...prevState,
|
|
34
|
+
status: "disabled"
|
|
35
|
+
};
|
|
36
|
+
case "add-secret":
|
|
37
|
+
return {
|
|
38
|
+
...prevState,
|
|
39
|
+
status: "add-secret-dialog"
|
|
40
|
+
};
|
|
41
|
+
case "failed-remove-secret":
|
|
42
|
+
return {
|
|
43
|
+
...prevState,
|
|
44
|
+
status: "enabled"
|
|
45
|
+
};
|
|
46
|
+
case "failed-add-secret":
|
|
47
|
+
return {
|
|
48
|
+
...prevState,
|
|
49
|
+
status: "add-secret-dialog"
|
|
50
|
+
};
|
|
51
|
+
default:
|
|
52
|
+
return prevState;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function VercelProtectionBypassTool() {
|
|
56
|
+
const $ = c(25);
|
|
57
|
+
let t0;
|
|
58
|
+
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
|
|
59
|
+
apiVersion
|
|
60
|
+
}, $[0] = t0) : t0 = $[0];
|
|
61
|
+
const client = useClient(t0), {
|
|
62
|
+
push: pushToast
|
|
63
|
+
} = useToast();
|
|
64
|
+
let t1;
|
|
65
|
+
$[1] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
|
|
66
|
+
status: "loading"
|
|
67
|
+
}, $[1] = t1) : t1 = $[1];
|
|
68
|
+
const [state, dispatch] = useReducer(reducer, t1), adding = state.status === "adding-secret", removing = state.status === "removing-secret";
|
|
69
|
+
let t2;
|
|
70
|
+
$[2] !== client || $[3] !== pushToast ? (t2 = (secret) => {
|
|
71
|
+
dispatch({
|
|
72
|
+
type: "save-secret"
|
|
73
|
+
}), enableVercelProtectionBypass(client, secret).then(() => {
|
|
74
|
+
dispatch({
|
|
75
|
+
type: "saved-secret"
|
|
76
|
+
}), pushToast({
|
|
77
|
+
status: "success",
|
|
78
|
+
title: "Protection bypass is now enabled"
|
|
79
|
+
});
|
|
80
|
+
}).catch((reason) => {
|
|
81
|
+
console.error(reason), pushToast({
|
|
82
|
+
status: "error",
|
|
83
|
+
title: "There was an error when trying to enable protection bypass. See the browser console for more information."
|
|
84
|
+
}), dispatch({
|
|
85
|
+
type: "failed-add-secret"
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}, $[2] = client, $[3] = pushToast, $[4] = t2) : t2 = $[4];
|
|
89
|
+
const handleEnable = t2;
|
|
90
|
+
let t3, t4;
|
|
91
|
+
$[5] !== client ? (t3 = () => {
|
|
92
|
+
const unsubscribe = subcribeToVercelProtectionBypass(client, (secret_0) => dispatch({
|
|
93
|
+
type: secret_0 ? "saved-secret" : "removed-secret"
|
|
94
|
+
}));
|
|
95
|
+
return () => unsubscribe();
|
|
96
|
+
}, t4 = [client], $[5] = client, $[6] = t3, $[7] = t4) : (t3 = $[6], t4 = $[7]), useEffect(t3, t4);
|
|
97
|
+
const enabled = state.status === "enabled" || removing;
|
|
98
|
+
let t5;
|
|
99
|
+
$[8] === Symbol.for("react.memo_cache_sentinel") ? (t5 = {
|
|
100
|
+
height: "100%",
|
|
101
|
+
alignItems: "center",
|
|
102
|
+
justifyContent: "center",
|
|
103
|
+
flexDirection: "column"
|
|
104
|
+
}, $[8] = t5) : t5 = $[8];
|
|
105
|
+
let t6;
|
|
106
|
+
$[9] === Symbol.for("react.memo_cache_sentinel") ? (t6 = {
|
|
107
|
+
maxWidth: 640
|
|
108
|
+
}, $[9] = t6) : t6 = $[9];
|
|
109
|
+
let t7, t8;
|
|
110
|
+
$[10] === Symbol.for("react.memo_cache_sentinel") ? (t7 = {
|
|
111
|
+
justifyItems: "flex-start",
|
|
112
|
+
textWrap: "pretty"
|
|
113
|
+
}, t8 = /* @__PURE__ */ jsx(Heading, { children: "Vercel Protection Bypass" }), $[10] = t7, $[11] = t8) : (t7 = $[10], t8 = $[11]);
|
|
114
|
+
let t9;
|
|
115
|
+
$[12] !== client || $[13] !== enabled || $[14] !== pushToast || $[15] !== removing || $[16] !== state.status ? (t9 = /* @__PURE__ */ jsx(Box, { sizing: "border", display: "flex", style: t5, children: /* @__PURE__ */ jsx(Stack, { space: 5, children: /* @__PURE__ */ jsx(Card, { padding: 4, style: t6, children: /* @__PURE__ */ jsxs(Stack, { space: 4, style: t7, children: [
|
|
116
|
+
t8,
|
|
117
|
+
enabled ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
118
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { style: {
|
|
119
|
+
textWrap: "pretty"
|
|
120
|
+
}, children: [
|
|
121
|
+
"Sanity Presentation is setup to use",
|
|
122
|
+
" ",
|
|
123
|
+
/* @__PURE__ */ jsx("a", { href: "https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation", target: "_blank", rel: "noreferrer", children: "protection bypass for automation" }),
|
|
124
|
+
" ",
|
|
125
|
+
"in order to display protected deployments in its preview iframe for the current Sanity dataset."
|
|
126
|
+
] }) }),
|
|
127
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: "You can turn off automatic protection bypass at any time by clicking the button below." }) }),
|
|
128
|
+
/* @__PURE__ */ jsx(Button, { mode: "ghost", tone: "critical", icon: /* @__PURE__ */ jsx(TrashIcon, {}), loading: removing, onClick: () => {
|
|
129
|
+
dispatch({
|
|
130
|
+
type: "remove-secret"
|
|
131
|
+
}), disableVercelProtectionBypass(client).then(() => {
|
|
132
|
+
pushToast({
|
|
133
|
+
status: "warning",
|
|
134
|
+
title: "Protection bypass is now disabled"
|
|
135
|
+
}), dispatch({
|
|
136
|
+
type: "removed-secret"
|
|
137
|
+
});
|
|
138
|
+
}).catch((reason_0) => {
|
|
139
|
+
console.error(reason_0), pushToast({
|
|
140
|
+
status: "error",
|
|
141
|
+
title: "There was an error when trying to disable protection bypass. See the browser console for more information."
|
|
142
|
+
}), dispatch({
|
|
143
|
+
type: "failed-remove-secret"
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}, text: "Remove secret" }),
|
|
147
|
+
/* @__PURE__ */ jsx(Text, { children: "Protection bypass remains enabled if this plugin is removed from your Sanity config." })
|
|
148
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
149
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { style: {
|
|
150
|
+
textWrap: "pretty"
|
|
151
|
+
}, children: [
|
|
152
|
+
"Follow the instructions on",
|
|
153
|
+
" ",
|
|
154
|
+
/* @__PURE__ */ jsx("a", { href: "https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation", target: "_blank", rel: "noreferrer", children: "how to enable protection bypass for automation" }),
|
|
155
|
+
"."
|
|
156
|
+
] }) }),
|
|
157
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: "This will setup a secret that Vercel exposes as an environment variable called VERCEL_AUTOMATION_BYPASS_SECRET, its value is the secret you need." }) }),
|
|
158
|
+
/* @__PURE__ */ jsx(Button, { mode: "ghost", icon: /* @__PURE__ */ jsx(AddIcon, {}), loading: state.status === "loading", onClick: () => {
|
|
159
|
+
dispatch({
|
|
160
|
+
type: "add-secret"
|
|
161
|
+
});
|
|
162
|
+
}, text: "Add secret" }),
|
|
163
|
+
/* @__PURE__ */ jsx(Text, { children: "If you're using Sanity Presentation Tool with multiple protected deployments ensure that they have the same secret set, as this tool will set a secret that is shared in your dataset with all instances of Presentation Tool." })
|
|
164
|
+
] })
|
|
165
|
+
] }) }) }) }), $[12] = client, $[13] = enabled, $[14] = pushToast, $[15] = removing, $[16] = state.status, $[17] = t9) : t9 = $[17];
|
|
166
|
+
let t10;
|
|
167
|
+
$[18] !== adding || $[19] !== handleEnable || $[20] !== state.status ? (t10 = (state.status === "add-secret-dialog" || state.status === "adding-secret") && /* @__PURE__ */ jsx(Dialog, { animate: !0, id: "add-secret-dialog", onClickOutside: () => dispatch({
|
|
168
|
+
type: "cancel-add-secret"
|
|
169
|
+
}), children: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsx("form", { onSubmit: (event) => {
|
|
170
|
+
event.preventDefault(), event.currentTarget.reportValidity();
|
|
171
|
+
const secret_1 = new FormData(event.currentTarget).get("secret");
|
|
172
|
+
secret_1 && handleEnable(secret_1);
|
|
173
|
+
}, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
174
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
175
|
+
/* @__PURE__ */ jsx(Text, { as: "label", weight: "semibold", size: 1, children: "Add bypass secret" }),
|
|
176
|
+
/* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "Make sure it's the same secret the Vercel deployment is using that's loaded in the preview iframe." }),
|
|
177
|
+
/* @__PURE__ */ jsx(TextInput, { name: "secret", onFocus: _temp, onBlur: _temp2, minLength: 32, maxLength: 32, autoComplete: "off", autoCapitalize: "off", autoCorrect: "off", spellCheck: "false", disabled: adding })
|
|
178
|
+
] }),
|
|
179
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", loading: adding, text: adding ? "Saving\u2026" : "Save", tone: "positive" })
|
|
180
|
+
] }) }) }) }), $[18] = adding, $[19] = handleEnable, $[20] = state.status, $[21] = t10) : t10 = $[21];
|
|
181
|
+
let t11;
|
|
182
|
+
return $[22] !== t10 || $[23] !== t9 ? (t11 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
183
|
+
t9,
|
|
184
|
+
t10
|
|
185
|
+
] }), $[22] = t10, $[23] = t9, $[24] = t11) : t11 = $[24], t11;
|
|
186
|
+
}
|
|
187
|
+
function _temp2(event_1) {
|
|
188
|
+
event_1.currentTarget.setCustomValidity(event_1.currentTarget.value.length == 32 ? "" : "Secret must be 32 characters long"), event_1.currentTarget.required = !0;
|
|
189
|
+
}
|
|
190
|
+
function _temp(event_0) {
|
|
191
|
+
event_0.currentTarget.setCustomValidity("");
|
|
192
|
+
}
|
|
193
|
+
export {
|
|
194
|
+
VercelProtectionBypassTool as default
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=VercelProtectionBypassTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VercelProtectionBypassTool.js","sources":["../../src/VercelProtectionBypassTool.tsx"],"sourcesContent":["import {AddIcon, TrashIcon} from '@sanity/icons'\nimport {apiVersion} from '@sanity/preview-url-secret/constants'\nimport {\n disableVercelProtectionBypass,\n enableVercelProtectionBypass,\n subcribeToVercelProtectionBypass,\n} from '@sanity/preview-url-secret/toggle-vercel-protection-bypass'\nimport {Box, Button, Card, Dialog, Heading, Stack, Text, TextInput, useToast} from '@sanity/ui'\nimport {useEffect, useReducer} from 'react'\nimport {useClient} from 'sanity'\n\ninterface State {\n status:\n | 'loading'\n | 'disabled'\n | 'add-secret-dialog'\n | 'adding-secret'\n | 'enabled'\n | 'removing-secret'\n}\ntype Action =\n | {type: 'add-secret'}\n | {type: 'save-secret'}\n | {type: 'cancel-add-secret'}\n | {type: 'failed-add-secret'}\n | {type: 'saved-secret'}\n | {type: 'remove-secret'}\n | {type: 'failed-remove-secret'}\n | {type: 'removed-secret'}\n\nfunction reducer(prevState: State, action: Action): State {\n switch (action.type) {\n case 'removed-secret':\n return {...prevState, status: 'disabled'}\n case 'remove-secret':\n return {...prevState, status: 'removing-secret'}\n case 'saved-secret':\n return {...prevState, status: 'enabled'}\n case 'save-secret':\n return {...prevState, status: 'adding-secret'}\n case 'cancel-add-secret':\n return {...prevState, status: 'disabled'}\n case 'add-secret':\n return {...prevState, status: 'add-secret-dialog'}\n case 'failed-remove-secret':\n return {...prevState, status: 'enabled'}\n case 'failed-add-secret':\n return {...prevState, status: 'add-secret-dialog'}\n default:\n return prevState\n }\n}\n\nexport default function VercelProtectionBypassTool(): React.JSX.Element {\n const client = useClient({apiVersion: apiVersion})\n const {push: pushToast} = useToast()\n const [state, dispatch] = useReducer(reducer, {status: 'loading'})\n const adding = state.status === 'adding-secret'\n const removing = state.status === 'removing-secret'\n\n const handleEnable = (secret: string) => {\n dispatch({type: 'save-secret'})\n enableVercelProtectionBypass(client, secret)\n .then(() => {\n dispatch({type: 'saved-secret'})\n pushToast({\n status: 'success',\n title: 'Protection bypass is now enabled',\n })\n })\n .catch((reason) => {\n // eslint-disable-next-line no-console\n console.error(reason)\n pushToast({\n status: 'error',\n title:\n 'There was an error when trying to enable protection bypass. See the browser console for more information.',\n })\n dispatch({type: 'failed-add-secret'})\n })\n }\n\n useEffect(() => {\n const unsubscribe = subcribeToVercelProtectionBypass(client, (secret) =>\n dispatch({type: secret ? 'saved-secret' : 'removed-secret'}),\n )\n return () => unsubscribe()\n }, [client])\n\n const enabled = state.status === 'enabled' || removing\n\n return (\n <>\n <Box\n sizing=\"border\"\n display=\"flex\"\n style={{\n height: '100%',\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n }}\n >\n <Stack space={5}>\n <Card padding={4} style={{maxWidth: 640}}>\n <Stack space={4} style={{justifyItems: 'flex-start', textWrap: 'pretty'}}>\n <Heading>Vercel Protection Bypass</Heading>\n {enabled ? (\n <>\n <Box>\n <Text style={{textWrap: 'pretty'}}>\n Sanity Presentation is setup to use{' '}\n <a\n href=\"https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n protection bypass for automation\n </a>{' '}\n in order to display protected deployments in its preview iframe for the\n current Sanity dataset.\n </Text>\n </Box>\n <Box>\n <Text>\n You can turn off automatic protection bypass at any time by clicking the\n button below.\n </Text>\n </Box>\n <Button\n mode=\"ghost\"\n tone=\"critical\"\n icon={<TrashIcon />}\n loading={removing}\n onClick={() => {\n dispatch({type: 'remove-secret'})\n disableVercelProtectionBypass(client)\n .then(() => {\n pushToast({\n status: 'warning',\n title: 'Protection bypass is now disabled',\n })\n dispatch({type: 'removed-secret'})\n })\n .catch((reason) => {\n // eslint-disable-next-line no-console\n console.error(reason)\n pushToast({\n status: 'error',\n title:\n 'There was an error when trying to disable protection bypass. See the browser console for more information.',\n })\n dispatch({type: 'failed-remove-secret'})\n })\n }}\n text=\"Remove secret\"\n />\n <Text>\n Protection bypass remains enabled if this plugin is removed from your Sanity\n config.\n </Text>\n </>\n ) : (\n <>\n <Box>\n <Text style={{textWrap: 'pretty'}}>\n Follow the instructions on{' '}\n <a\n href=\"https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n how to enable protection bypass for automation\n </a>\n .\n </Text>\n </Box>\n <Box>\n <Text>\n This will setup a secret that Vercel exposes as an environment variable called\n VERCEL_AUTOMATION_BYPASS_SECRET, its value is the secret you need.\n </Text>\n </Box>\n <Button\n mode=\"ghost\"\n icon={<AddIcon />}\n loading={state.status === 'loading'}\n onClick={() => {\n dispatch({type: 'add-secret'})\n }}\n text=\"Add secret\"\n />\n <Text>\n If you're using Sanity Presentation Tool with multiple protected\n deployments ensure that they have the same secret set, as this tool will set a\n secret that is shared in your dataset with all instances of Presentation Tool.\n </Text>\n </>\n )}\n </Stack>\n </Card>\n </Stack>\n </Box>\n {(state.status === 'add-secret-dialog' || state.status === 'adding-secret') && (\n <Dialog\n animate\n id=\"add-secret-dialog\"\n onClickOutside={() => dispatch({type: 'cancel-add-secret'})}\n >\n <Card padding={3}>\n <form\n onSubmit={(event) => {\n event.preventDefault()\n event.currentTarget.reportValidity()\n const formData = new FormData(event.currentTarget)\n const secret = formData.get('secret') as string\n if (secret) handleEnable(secret)\n }}\n >\n <Stack space={3}>\n <Stack space={2}>\n <Text as=\"label\" weight=\"semibold\" size={1}>\n Add bypass secret\n </Text>\n <Text muted size={1}>\n {`Make sure it's the same secret the Vercel deployment is using that's loaded in the preview iframe.`}\n </Text>\n <TextInput\n name=\"secret\"\n onFocus={(event) => {\n event.currentTarget.setCustomValidity('')\n }}\n onBlur={(event) => {\n event.currentTarget.setCustomValidity(\n event.currentTarget.value.length == 32\n ? ''\n : 'Secret must be 32 characters long',\n )\n event.currentTarget.required = true\n }}\n minLength={32}\n maxLength={32}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n spellCheck=\"false\"\n disabled={adding}\n />\n </Stack>\n <Button\n type=\"submit\"\n loading={adding}\n text={adding ? 'Saving…' : 'Save'}\n tone=\"positive\"\n />\n </Stack>\n </form>\n </Card>\n </Dialog>\n )}\n </>\n )\n}\n"],"names":["reducer","prevState","action","type","status","VercelProtectionBypassTool","$","_c","t0","Symbol","for","apiVersion","client","useClient","push","pushToast","useToast","t1","state","dispatch","useReducer","adding","removing","t2","secret","enableVercelProtectionBypass","then","title","catch","reason","error","handleEnable","t3","t4","unsubscribe","subcribeToVercelProtectionBypass","secret_0","useEffect","enabled","t5","height","alignItems","justifyContent","flexDirection","t6","maxWidth","t7","t8","justifyItems","textWrap","t9","disableVercelProtectionBypass","reason_0","t10","event","preventDefault","currentTarget","reportValidity","secret_1","FormData","get","_temp","_temp2","t11","event_1","setCustomValidity","value","length","required","event_0"],"mappings":"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"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
+
var react = require("react"), sanity = require("sanity");
|
|
4
|
+
const id = "vercel-protection-bypass", vercelProtectionBypassTool = sanity.definePlugin((options) => {
|
|
5
|
+
const {
|
|
6
|
+
name,
|
|
7
|
+
title,
|
|
8
|
+
icon,
|
|
9
|
+
...config
|
|
10
|
+
} = options || {};
|
|
11
|
+
return {
|
|
12
|
+
name: `@sanity/preview-url-secret/${id}`,
|
|
13
|
+
tools: [{
|
|
14
|
+
name: name || "vercel-protection-bypass",
|
|
15
|
+
title: title || "Vercel Protection Bypass",
|
|
16
|
+
icon,
|
|
17
|
+
component: react.lazy(() => Promise.resolve().then(function() {
|
|
18
|
+
return require("./_chunks-cjs/VercelProtectionBypassTool.cjs");
|
|
19
|
+
})),
|
|
20
|
+
options: config,
|
|
21
|
+
__internalApplicationType: `sanity/${id}`
|
|
22
|
+
}]
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
exports.vercelProtectionBypassTool = vercelProtectionBypassTool;
|
|
26
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import {lazy} from 'react'\nimport {definePlugin} from 'sanity'\n\nconst id = 'vercel-protection-bypass'\n\nexport interface VercelProtectionBypassConfig {\n name?: string\n title?: string\n icon?: React.ComponentType\n}\n\nexport const vercelProtectionBypassTool = definePlugin<VercelProtectionBypassConfig | void>(\n (options) => {\n const {name, title, icon, ...config} = options || {}\n return {\n name: `@sanity/preview-url-secret/${id}`,\n tools: [\n {\n name: name || 'vercel-protection-bypass',\n title: title || 'Vercel Protection Bypass',\n icon: icon,\n component: lazy(() => import('./VercelProtectionBypassTool')),\n options: config,\n __internalApplicationType: `sanity/${id}`,\n },\n ],\n }\n },\n)\n"],"names":["id","vercelProtectionBypassTool","definePlugin","options","name","title","icon","config","tools","component","lazy","__internalApplicationType"],"mappings":";;;AAGA,MAAMA,KAAK,4BAQEC,6BAA6BC,OAAAA,aACvCC,CAAY,YAAA;AACL,QAAA;AAAA,IAACC;AAAAA,IAAMC;AAAAA,IAAOC;AAAAA,IAAM,GAAGC;AAAAA,EAAM,IAAIJ,WAAW,CAAC;AAC5C,SAAA;AAAA,IACLC,MAAM,8BAA8BJ,EAAE;AAAA,IACtCQ,OAAO,CACL;AAAA,MACEJ,MAAMA,QAAQ;AAAA,MACdC,OAAOA,SAAS;AAAA,MAChBC;AAAAA,MACAG,WAAWC,MAAAA,KAAK,MAAM,QAAO,QAAA,EAAA,KAAA,WAAA;AAAA,eAAA,QAAA,8CAA8B;AAAA,QAAC;AAAA,MAC5DP,SAASI;AAAAA,MACTI,2BAA2B,UAAUX,EAAE;AAAA,IACxC,CAAA;AAAA,EAEL;AACF,CACF;;"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {Plugin as Plugin_2} from 'sanity'
|
|
2
|
+
|
|
3
|
+
export declare interface VercelProtectionBypassConfig {
|
|
4
|
+
name?: string
|
|
5
|
+
title?: string
|
|
6
|
+
icon?: React.ComponentType
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export declare const vercelProtectionBypassTool: Plugin_2<void | VercelProtectionBypassConfig>
|
|
10
|
+
|
|
11
|
+
export {}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {Plugin as Plugin_2} from 'sanity'
|
|
2
|
+
|
|
3
|
+
export declare interface VercelProtectionBypassConfig {
|
|
4
|
+
name?: string
|
|
5
|
+
title?: string
|
|
6
|
+
icon?: React.ComponentType
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export declare const vercelProtectionBypassTool: Plugin_2<void | VercelProtectionBypassConfig>
|
|
10
|
+
|
|
11
|
+
export {}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { lazy } from "react";
|
|
2
|
+
import { definePlugin } from "sanity";
|
|
3
|
+
const id = "vercel-protection-bypass", vercelProtectionBypassTool = definePlugin((options) => {
|
|
4
|
+
const {
|
|
5
|
+
name,
|
|
6
|
+
title,
|
|
7
|
+
icon,
|
|
8
|
+
...config
|
|
9
|
+
} = options || {};
|
|
10
|
+
return {
|
|
11
|
+
name: `@sanity/preview-url-secret/${id}`,
|
|
12
|
+
tools: [{
|
|
13
|
+
name: name || "vercel-protection-bypass",
|
|
14
|
+
title: title || "Vercel Protection Bypass",
|
|
15
|
+
icon,
|
|
16
|
+
component: lazy(() => import("./_chunks-es/VercelProtectionBypassTool.js")),
|
|
17
|
+
options: config,
|
|
18
|
+
__internalApplicationType: `sanity/${id}`
|
|
19
|
+
}]
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
export {
|
|
23
|
+
vercelProtectionBypassTool
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import {lazy} from 'react'\nimport {definePlugin} from 'sanity'\n\nconst id = 'vercel-protection-bypass'\n\nexport interface VercelProtectionBypassConfig {\n name?: string\n title?: string\n icon?: React.ComponentType\n}\n\nexport const vercelProtectionBypassTool = definePlugin<VercelProtectionBypassConfig | void>(\n (options) => {\n const {name, title, icon, ...config} = options || {}\n return {\n name: `@sanity/preview-url-secret/${id}`,\n tools: [\n {\n name: name || 'vercel-protection-bypass',\n title: title || 'Vercel Protection Bypass',\n icon: icon,\n component: lazy(() => import('./VercelProtectionBypassTool')),\n options: config,\n __internalApplicationType: `sanity/${id}`,\n },\n ],\n }\n },\n)\n"],"names":["id","vercelProtectionBypassTool","definePlugin","options","name","title","icon","config","tools","component","lazy","__internalApplicationType"],"mappings":";;AAGA,MAAMA,KAAK,4BAQEC,6BAA6BC,aACvCC,CAAY,YAAA;AACL,QAAA;AAAA,IAACC;AAAAA,IAAMC;AAAAA,IAAOC;AAAAA,IAAM,GAAGC;AAAAA,EAAM,IAAIJ,WAAW,CAAC;AAC5C,SAAA;AAAA,IACLC,MAAM,8BAA8BJ,EAAE;AAAA,IACtCQ,OAAO,CACL;AAAA,MACEJ,MAAMA,QAAQ;AAAA,MACdC,OAAOA,SAAS;AAAA,MAChBC;AAAAA,MACAG,WAAWC,KAAK,MAAM,OAAO,4CAA8B,CAAC;AAAA,MAC5DP,SAASI;AAAAA,MACTI,2BAA2B,UAAUX,EAAE;AAAA,IACxC,CAAA;AAAA,EAEL;AACF,CACF;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sanity/vercel-protection-bypass",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"homepage": "https://github.com/sanity-io/visual-editing/tree/main/packages/vercel-protection-bypass#readme",
|
|
5
|
+
"bugs": {
|
|
6
|
+
"url": "https://github.com/sanity-io/visual-editing/issues"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+ssh://git@github.com/sanity-io/visual-editing.git",
|
|
11
|
+
"directory": "packages/vercel-protection-bypass"
|
|
12
|
+
},
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Sanity.io <hello@sanity.io>",
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"type": "module",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"source": "./src/index.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.cjs",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"main": "./dist/index.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"src",
|
|
32
|
+
"!src/**/*.test.ts",
|
|
33
|
+
"!src/**/*.test-d.ts",
|
|
34
|
+
"CHANGELOG.md"
|
|
35
|
+
],
|
|
36
|
+
"browserslist": "extends @sanity/browserslist-config",
|
|
37
|
+
"prettier": "@repo/prettier-config",
|
|
38
|
+
"eslintConfig": {
|
|
39
|
+
"extends": [
|
|
40
|
+
"@repo/eslint-config"
|
|
41
|
+
],
|
|
42
|
+
"root": true
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@sanity/icons": "^3.5.7",
|
|
46
|
+
"@sanity/ui": "^2.11.1",
|
|
47
|
+
"react-compiler-runtime": "19.0.0-beta-55955c9-20241229",
|
|
48
|
+
"@sanity/preview-url-secret": "^2.1.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@sanity/pkg-utils": "6.13.4",
|
|
52
|
+
"babel-plugin-react-compiler": "19.0.0-beta-63e3235-20250105",
|
|
53
|
+
"eslint": "^8.57.1",
|
|
54
|
+
"react": "^19.0.0",
|
|
55
|
+
"sanity": "3.69.0",
|
|
56
|
+
"typescript": "5.7.2",
|
|
57
|
+
"vitest": "^2.1.8",
|
|
58
|
+
"@repo/eslint-config": "0.0.0",
|
|
59
|
+
"@repo/package.config": "0.0.0",
|
|
60
|
+
"@repo/prettier-config": "0.0.0"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"react": "^18.3 || ^19",
|
|
64
|
+
"sanity": "^3.69.0"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=18"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public"
|
|
71
|
+
},
|
|
72
|
+
"scripts": {
|
|
73
|
+
"build": "pkg build --strict --check --clean",
|
|
74
|
+
"dev": "pkg build --strict",
|
|
75
|
+
"lint": "eslint --cache .",
|
|
76
|
+
"test": "vitest --pass-with-no-tests --typecheck"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import {AddIcon, TrashIcon} from '@sanity/icons'
|
|
2
|
+
import {apiVersion} from '@sanity/preview-url-secret/constants'
|
|
3
|
+
import {
|
|
4
|
+
disableVercelProtectionBypass,
|
|
5
|
+
enableVercelProtectionBypass,
|
|
6
|
+
subcribeToVercelProtectionBypass,
|
|
7
|
+
} from '@sanity/preview-url-secret/toggle-vercel-protection-bypass'
|
|
8
|
+
import {Box, Button, Card, Dialog, Heading, Stack, Text, TextInput, useToast} from '@sanity/ui'
|
|
9
|
+
import {useEffect, useReducer} from 'react'
|
|
10
|
+
import {useClient} from 'sanity'
|
|
11
|
+
|
|
12
|
+
interface State {
|
|
13
|
+
status:
|
|
14
|
+
| 'loading'
|
|
15
|
+
| 'disabled'
|
|
16
|
+
| 'add-secret-dialog'
|
|
17
|
+
| 'adding-secret'
|
|
18
|
+
| 'enabled'
|
|
19
|
+
| 'removing-secret'
|
|
20
|
+
}
|
|
21
|
+
type Action =
|
|
22
|
+
| {type: 'add-secret'}
|
|
23
|
+
| {type: 'save-secret'}
|
|
24
|
+
| {type: 'cancel-add-secret'}
|
|
25
|
+
| {type: 'failed-add-secret'}
|
|
26
|
+
| {type: 'saved-secret'}
|
|
27
|
+
| {type: 'remove-secret'}
|
|
28
|
+
| {type: 'failed-remove-secret'}
|
|
29
|
+
| {type: 'removed-secret'}
|
|
30
|
+
|
|
31
|
+
function reducer(prevState: State, action: Action): State {
|
|
32
|
+
switch (action.type) {
|
|
33
|
+
case 'removed-secret':
|
|
34
|
+
return {...prevState, status: 'disabled'}
|
|
35
|
+
case 'remove-secret':
|
|
36
|
+
return {...prevState, status: 'removing-secret'}
|
|
37
|
+
case 'saved-secret':
|
|
38
|
+
return {...prevState, status: 'enabled'}
|
|
39
|
+
case 'save-secret':
|
|
40
|
+
return {...prevState, status: 'adding-secret'}
|
|
41
|
+
case 'cancel-add-secret':
|
|
42
|
+
return {...prevState, status: 'disabled'}
|
|
43
|
+
case 'add-secret':
|
|
44
|
+
return {...prevState, status: 'add-secret-dialog'}
|
|
45
|
+
case 'failed-remove-secret':
|
|
46
|
+
return {...prevState, status: 'enabled'}
|
|
47
|
+
case 'failed-add-secret':
|
|
48
|
+
return {...prevState, status: 'add-secret-dialog'}
|
|
49
|
+
default:
|
|
50
|
+
return prevState
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default function VercelProtectionBypassTool(): React.JSX.Element {
|
|
55
|
+
const client = useClient({apiVersion: apiVersion})
|
|
56
|
+
const {push: pushToast} = useToast()
|
|
57
|
+
const [state, dispatch] = useReducer(reducer, {status: 'loading'})
|
|
58
|
+
const adding = state.status === 'adding-secret'
|
|
59
|
+
const removing = state.status === 'removing-secret'
|
|
60
|
+
|
|
61
|
+
const handleEnable = (secret: string) => {
|
|
62
|
+
dispatch({type: 'save-secret'})
|
|
63
|
+
enableVercelProtectionBypass(client, secret)
|
|
64
|
+
.then(() => {
|
|
65
|
+
dispatch({type: 'saved-secret'})
|
|
66
|
+
pushToast({
|
|
67
|
+
status: 'success',
|
|
68
|
+
title: 'Protection bypass is now enabled',
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
.catch((reason) => {
|
|
72
|
+
// eslint-disable-next-line no-console
|
|
73
|
+
console.error(reason)
|
|
74
|
+
pushToast({
|
|
75
|
+
status: 'error',
|
|
76
|
+
title:
|
|
77
|
+
'There was an error when trying to enable protection bypass. See the browser console for more information.',
|
|
78
|
+
})
|
|
79
|
+
dispatch({type: 'failed-add-secret'})
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const unsubscribe = subcribeToVercelProtectionBypass(client, (secret) =>
|
|
85
|
+
dispatch({type: secret ? 'saved-secret' : 'removed-secret'}),
|
|
86
|
+
)
|
|
87
|
+
return () => unsubscribe()
|
|
88
|
+
}, [client])
|
|
89
|
+
|
|
90
|
+
const enabled = state.status === 'enabled' || removing
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<Box
|
|
95
|
+
sizing="border"
|
|
96
|
+
display="flex"
|
|
97
|
+
style={{
|
|
98
|
+
height: '100%',
|
|
99
|
+
alignItems: 'center',
|
|
100
|
+
justifyContent: 'center',
|
|
101
|
+
flexDirection: 'column',
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
<Stack space={5}>
|
|
105
|
+
<Card padding={4} style={{maxWidth: 640}}>
|
|
106
|
+
<Stack space={4} style={{justifyItems: 'flex-start', textWrap: 'pretty'}}>
|
|
107
|
+
<Heading>Vercel Protection Bypass</Heading>
|
|
108
|
+
{enabled ? (
|
|
109
|
+
<>
|
|
110
|
+
<Box>
|
|
111
|
+
<Text style={{textWrap: 'pretty'}}>
|
|
112
|
+
Sanity Presentation is setup to use{' '}
|
|
113
|
+
<a
|
|
114
|
+
href="https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation"
|
|
115
|
+
target="_blank"
|
|
116
|
+
rel="noreferrer"
|
|
117
|
+
>
|
|
118
|
+
protection bypass for automation
|
|
119
|
+
</a>{' '}
|
|
120
|
+
in order to display protected deployments in its preview iframe for the
|
|
121
|
+
current Sanity dataset.
|
|
122
|
+
</Text>
|
|
123
|
+
</Box>
|
|
124
|
+
<Box>
|
|
125
|
+
<Text>
|
|
126
|
+
You can turn off automatic protection bypass at any time by clicking the
|
|
127
|
+
button below.
|
|
128
|
+
</Text>
|
|
129
|
+
</Box>
|
|
130
|
+
<Button
|
|
131
|
+
mode="ghost"
|
|
132
|
+
tone="critical"
|
|
133
|
+
icon={<TrashIcon />}
|
|
134
|
+
loading={removing}
|
|
135
|
+
onClick={() => {
|
|
136
|
+
dispatch({type: 'remove-secret'})
|
|
137
|
+
disableVercelProtectionBypass(client)
|
|
138
|
+
.then(() => {
|
|
139
|
+
pushToast({
|
|
140
|
+
status: 'warning',
|
|
141
|
+
title: 'Protection bypass is now disabled',
|
|
142
|
+
})
|
|
143
|
+
dispatch({type: 'removed-secret'})
|
|
144
|
+
})
|
|
145
|
+
.catch((reason) => {
|
|
146
|
+
// eslint-disable-next-line no-console
|
|
147
|
+
console.error(reason)
|
|
148
|
+
pushToast({
|
|
149
|
+
status: 'error',
|
|
150
|
+
title:
|
|
151
|
+
'There was an error when trying to disable protection bypass. See the browser console for more information.',
|
|
152
|
+
})
|
|
153
|
+
dispatch({type: 'failed-remove-secret'})
|
|
154
|
+
})
|
|
155
|
+
}}
|
|
156
|
+
text="Remove secret"
|
|
157
|
+
/>
|
|
158
|
+
<Text>
|
|
159
|
+
Protection bypass remains enabled if this plugin is removed from your Sanity
|
|
160
|
+
config.
|
|
161
|
+
</Text>
|
|
162
|
+
</>
|
|
163
|
+
) : (
|
|
164
|
+
<>
|
|
165
|
+
<Box>
|
|
166
|
+
<Text style={{textWrap: 'pretty'}}>
|
|
167
|
+
Follow the instructions on{' '}
|
|
168
|
+
<a
|
|
169
|
+
href="https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation"
|
|
170
|
+
target="_blank"
|
|
171
|
+
rel="noreferrer"
|
|
172
|
+
>
|
|
173
|
+
how to enable protection bypass for automation
|
|
174
|
+
</a>
|
|
175
|
+
.
|
|
176
|
+
</Text>
|
|
177
|
+
</Box>
|
|
178
|
+
<Box>
|
|
179
|
+
<Text>
|
|
180
|
+
This will setup a secret that Vercel exposes as an environment variable called
|
|
181
|
+
VERCEL_AUTOMATION_BYPASS_SECRET, its value is the secret you need.
|
|
182
|
+
</Text>
|
|
183
|
+
</Box>
|
|
184
|
+
<Button
|
|
185
|
+
mode="ghost"
|
|
186
|
+
icon={<AddIcon />}
|
|
187
|
+
loading={state.status === 'loading'}
|
|
188
|
+
onClick={() => {
|
|
189
|
+
dispatch({type: 'add-secret'})
|
|
190
|
+
}}
|
|
191
|
+
text="Add secret"
|
|
192
|
+
/>
|
|
193
|
+
<Text>
|
|
194
|
+
If you're using Sanity Presentation Tool with multiple protected
|
|
195
|
+
deployments ensure that they have the same secret set, as this tool will set a
|
|
196
|
+
secret that is shared in your dataset with all instances of Presentation Tool.
|
|
197
|
+
</Text>
|
|
198
|
+
</>
|
|
199
|
+
)}
|
|
200
|
+
</Stack>
|
|
201
|
+
</Card>
|
|
202
|
+
</Stack>
|
|
203
|
+
</Box>
|
|
204
|
+
{(state.status === 'add-secret-dialog' || state.status === 'adding-secret') && (
|
|
205
|
+
<Dialog
|
|
206
|
+
animate
|
|
207
|
+
id="add-secret-dialog"
|
|
208
|
+
onClickOutside={() => dispatch({type: 'cancel-add-secret'})}
|
|
209
|
+
>
|
|
210
|
+
<Card padding={3}>
|
|
211
|
+
<form
|
|
212
|
+
onSubmit={(event) => {
|
|
213
|
+
event.preventDefault()
|
|
214
|
+
event.currentTarget.reportValidity()
|
|
215
|
+
const formData = new FormData(event.currentTarget)
|
|
216
|
+
const secret = formData.get('secret') as string
|
|
217
|
+
if (secret) handleEnable(secret)
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
220
|
+
<Stack space={3}>
|
|
221
|
+
<Stack space={2}>
|
|
222
|
+
<Text as="label" weight="semibold" size={1}>
|
|
223
|
+
Add bypass secret
|
|
224
|
+
</Text>
|
|
225
|
+
<Text muted size={1}>
|
|
226
|
+
{`Make sure it's the same secret the Vercel deployment is using that's loaded in the preview iframe.`}
|
|
227
|
+
</Text>
|
|
228
|
+
<TextInput
|
|
229
|
+
name="secret"
|
|
230
|
+
onFocus={(event) => {
|
|
231
|
+
event.currentTarget.setCustomValidity('')
|
|
232
|
+
}}
|
|
233
|
+
onBlur={(event) => {
|
|
234
|
+
event.currentTarget.setCustomValidity(
|
|
235
|
+
event.currentTarget.value.length == 32
|
|
236
|
+
? ''
|
|
237
|
+
: 'Secret must be 32 characters long',
|
|
238
|
+
)
|
|
239
|
+
event.currentTarget.required = true
|
|
240
|
+
}}
|
|
241
|
+
minLength={32}
|
|
242
|
+
maxLength={32}
|
|
243
|
+
autoComplete="off"
|
|
244
|
+
autoCapitalize="off"
|
|
245
|
+
autoCorrect="off"
|
|
246
|
+
spellCheck="false"
|
|
247
|
+
disabled={adding}
|
|
248
|
+
/>
|
|
249
|
+
</Stack>
|
|
250
|
+
<Button
|
|
251
|
+
type="submit"
|
|
252
|
+
loading={adding}
|
|
253
|
+
text={adding ? 'Saving…' : 'Save'}
|
|
254
|
+
tone="positive"
|
|
255
|
+
/>
|
|
256
|
+
</Stack>
|
|
257
|
+
</form>
|
|
258
|
+
</Card>
|
|
259
|
+
</Dialog>
|
|
260
|
+
)}
|
|
261
|
+
</>
|
|
262
|
+
)
|
|
263
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {lazy} from 'react'
|
|
2
|
+
import {definePlugin} from 'sanity'
|
|
3
|
+
|
|
4
|
+
const id = 'vercel-protection-bypass'
|
|
5
|
+
|
|
6
|
+
export interface VercelProtectionBypassConfig {
|
|
7
|
+
name?: string
|
|
8
|
+
title?: string
|
|
9
|
+
icon?: React.ComponentType
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const vercelProtectionBypassTool = definePlugin<VercelProtectionBypassConfig | void>(
|
|
13
|
+
(options) => {
|
|
14
|
+
const {name, title, icon, ...config} = options || {}
|
|
15
|
+
return {
|
|
16
|
+
name: `@sanity/preview-url-secret/${id}`,
|
|
17
|
+
tools: [
|
|
18
|
+
{
|
|
19
|
+
name: name || 'vercel-protection-bypass',
|
|
20
|
+
title: title || 'Vercel Protection Bypass',
|
|
21
|
+
icon: icon,
|
|
22
|
+
component: lazy(() => import('./VercelProtectionBypassTool')),
|
|
23
|
+
options: config,
|
|
24
|
+
__internalApplicationType: `sanity/${id}`,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
)
|