@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 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
+ [![npm stat](https://img.shields.io/npm/dm/@sanity/vercel-protection-bypass.svg?style=flat-square)](https://npm-stat.com/charts.html?package=@sanity/vercel-protection-bypass)
4
+ [![npm version](https://img.shields.io/npm/v/@sanity/vercel-protection-bypass.svg?style=flat-square)](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&apos;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&apos;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;;"}
@@ -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 {}
@@ -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&apos;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
+ )