@sanity/vercel-protection-bypass 3.0.0 → 4.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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @sanity/vercel-protection-bypass
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#26](https://github.com/sanity-io/plugins/pull/26) [`32fb288`](https://github.com/sanity-io/plugins/commit/32fb28823efb7b99b8c884dca475ab16fef4883a) Thanks [@stipsan](https://github.com/stipsan)! - Require React 19.2 or later
8
+
9
+ - [#26](https://github.com/sanity-io/plugins/pull/26) [`32fb288`](https://github.com/sanity-io/plugins/commit/32fb28823efb7b99b8c884dca475ab16fef4883a) Thanks [@stipsan](https://github.com/stipsan)! - Require Sanity Studio v4
10
+
11
+ ## 3.1.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [`d090d93`](https://github.com/sanity-io/plugins/commit/d090d939e29a2aa46ccf1e1f18a63eb383630bdd) Thanks [@stipsan](https://github.com/stipsan)! - Add schema type for debugging
16
+
17
+ ### Patch Changes
18
+
19
+ - [`4f82b31`](https://github.com/sanity-io/plugins/commit/4f82b3120b3006821a74f444589ac3e752475c4e) Thanks [@stipsan](https://github.com/stipsan)! - Stop publishing src folder to npm
20
+
3
21
  ## 3.0.0
4
22
 
5
23
  ### Major Changes
package/README.md CHANGED
@@ -3,6 +3,9 @@
3
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
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
5
 
6
+ > [!IMPORTANT]
7
+ > This plugin requires React 19.2 or later, and Sanity Studio v4.
8
+
6
9
  ```sh
7
10
  npm install @sanity/vercel-protection-bypass
8
11
  ```
@@ -1,57 +1,10 @@
1
- import { jsxs, Fragment, jsx } from "react/jsx-runtime";
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { c } from "react-compiler-runtime";
3
- import { useReducer, useEffect } from "react";
3
+ import { useState, Suspense, useActionState, use, useTransition, useEffectEvent, useEffect, Activity } from "react";
4
4
  import { useClient } from "sanity";
5
5
  import { TrashIcon, AddIcon } from "@sanity/icons";
6
- import { apiVersion, vercelProtectionBypassSchemaId, vercelProtectionBypassSchemaType, tag } from "@sanity/preview-url-secret/constants";
7
- import { subscribeToVercelProtectionBypass } from "@sanity/preview-url-secret/toggle-vercel-protection-bypass";
8
- import { useToast, Heading, Box, Stack, Card, Text, Button, Dialog, TextInput } from "@sanity/ui";
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
- }
6
+ import { apiVersion, fetchVercelProtectionBypassSecret, vercelProtectionBypassSchemaId, vercelProtectionBypassSchemaType, tag } from "@sanity/preview-url-secret/constants";
7
+ import { Flex, Spinner, useToast, Heading, Box, Stack, Card, Text, Button, TextInput, Dialog } from "@sanity/ui";
55
8
  async function enableVercelProtectionBypass(client, secret) {
56
9
  const patch = client.patch(vercelProtectionBypassSchemaId).set({
57
10
  secret
@@ -75,67 +28,104 @@ async function disableVercelProtectionBypass(client) {
75
28
  });
76
29
  }
77
30
  function VercelProtectionBypassTool() {
78
- const $ = c(25);
31
+ const $ = c(9);
79
32
  let t0;
80
33
  $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
81
34
  apiVersion
82
35
  }, $[0] = t0) : t0 = $[0];
83
- const client = useClient(t0), {
36
+ const client = useClient(t0);
37
+ let t1;
38
+ $[1] !== client ? (t1 = async function(lastLiveEventId) {
39
+ const {
40
+ result,
41
+ syncTags
42
+ } = await client.fetch(fetchVercelProtectionBypassSecret, {}, {
43
+ filterResponse: !1,
44
+ lastLiveEventId,
45
+ tag: "preview-url-secret.fetch-vercel-bypass-protection-secret"
46
+ });
47
+ return {
48
+ secret: result,
49
+ syncTags: syncTags ?? []
50
+ };
51
+ }, $[1] = client, $[2] = t1) : t1 = $[2];
52
+ const fetchSecret = t1;
53
+ let t2;
54
+ $[3] !== fetchSecret ? (t2 = () => fetchSecret(null), $[3] = fetchSecret, $[4] = t2) : t2 = $[4];
55
+ const [initialStatePromise] = useState(t2);
56
+ let t3;
57
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(Flex, { align: "center", direction: "column", height: "fill", justify: "center", style: {
58
+ width: "100%"
59
+ }, children: /* @__PURE__ */ jsx(Spinner, {}) }), $[5] = t3) : t3 = $[5];
60
+ let t4;
61
+ return $[6] !== fetchSecret || $[7] !== initialStatePromise ? (t4 = /* @__PURE__ */ jsx(Suspense, { fallback: t3, children: /* @__PURE__ */ jsx(Layout, { initialStatePromise, fetchSecret }) }), $[6] = fetchSecret, $[7] = initialStatePromise, $[8] = t4) : t4 = $[8], t4;
62
+ }
63
+ function Layout(t0) {
64
+ const $ = c(29), {
65
+ initialStatePromise,
66
+ fetchSecret
67
+ } = t0, {
84
68
  push: pushToast
85
- } = useToast();
69
+ } = useToast(), [isDialogOpen, setIsDialogOpen] = useState(!1);
86
70
  let t1;
87
- $[1] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
88
- status: "loading"
89
- }, $[1] = t1) : t1 = $[1];
90
- const [state, dispatch] = useReducer(reducer, t1), adding = state.status === "adding-secret", removing = state.status === "removing-secret";
71
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
72
+ apiVersion
73
+ }, $[0] = t1) : t1 = $[0];
74
+ const client = useClient(t1);
91
75
  let t2;
92
- $[2] !== client || $[3] !== pushToast ? (t2 = (secret) => {
93
- dispatch({
94
- type: "save-secret"
95
- }), enableVercelProtectionBypass(client, secret).then(() => {
96
- dispatch({
97
- type: "saved-secret"
98
- }), pushToast({
99
- status: "success",
100
- title: "Protection bypass is now enabled"
101
- });
102
- }).catch((reason) => {
103
- console.error(reason), pushToast({
104
- status: "error",
105
- title: "There was an error when trying to enable protection bypass. See the browser console for more information."
106
- }), dispatch({
107
- type: "failed-add-secret"
108
- });
109
- });
110
- }, $[2] = client, $[3] = pushToast, $[4] = t2) : t2 = $[4];
111
- const handleEnable = t2;
112
- let t3, t4;
113
- $[5] !== client ? (t3 = () => {
114
- const unsubscribe = subscribeToVercelProtectionBypass(client, (secret_0) => dispatch({
115
- type: secret_0 ? "saved-secret" : "removed-secret"
116
- }));
117
- return () => unsubscribe();
118
- }, t4 = [client], $[5] = client, $[6] = t3, $[7] = t4) : (t3 = $[6], t4 = $[7]), useEffect(t3, t4);
119
- const enabled = state.status === "enabled" || removing;
120
- let t5;
121
- $[8] === Symbol.for("react.memo_cache_sentinel") ? (t5 = {
76
+ $[1] !== client || $[2] !== fetchSecret || $[3] !== pushToast ? (t2 = async (prevState, formData) => {
77
+ const action = formData.get("action");
78
+ switch (action) {
79
+ case "remove-secret":
80
+ return disableVercelProtectionBypass(client).then(() => (pushToast({
81
+ status: "warning",
82
+ title: "Protection bypass is now disabled"
83
+ }), {
84
+ ...prevState,
85
+ secret: null
86
+ })).catch((reason_0) => (console.error(reason_0), pushToast({
87
+ status: "error",
88
+ title: "There was an error when trying to disable protection bypass. See the browser console for more information."
89
+ }), prevState));
90
+ case "add-secret": {
91
+ const secret = formData.get("secret");
92
+ return enableVercelProtectionBypass(client, secret).then(() => (pushToast({
93
+ status: "success",
94
+ title: "Protection bypass is now enabled"
95
+ }), setIsDialogOpen(!1), {
96
+ ...prevState,
97
+ secret
98
+ })).catch((reason) => (console.error(reason), pushToast({
99
+ status: "error",
100
+ title: "There was an error when trying to enable protection bypass. See the browser console for more information."
101
+ }), prevState));
102
+ }
103
+ case "refresh-secret":
104
+ return fetchSecret(formData.get("lastLiveEventId"));
105
+ default:
106
+ throw new Error(`Unknown action: ${action}`);
107
+ }
108
+ }, $[1] = client, $[2] = fetchSecret, $[3] = pushToast, $[4] = t2) : t2 = $[4];
109
+ const action_0 = t2, [formState, formAction, isPending] = useActionState(action_0, use(initialStatePromise)), isBackgroundRefetch = useRefetchOnLiveEvent(client, formState, formAction), loading = isPending && !isBackgroundRefetch, enabled = !!formState.secret;
110
+ let t3;
111
+ $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = {
122
112
  height: "100%",
123
113
  alignItems: "center",
124
114
  justifyContent: "center",
125
115
  flexDirection: "column"
126
- }, $[8] = t5) : t5 = $[8];
127
- let t6;
128
- $[9] === Symbol.for("react.memo_cache_sentinel") ? (t6 = {
116
+ }, $[5] = t3) : t3 = $[5];
117
+ let t4;
118
+ $[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = {
129
119
  maxWidth: 640
130
- }, $[9] = t6) : t6 = $[9];
131
- let t7, t8;
132
- $[10] === Symbol.for("react.memo_cache_sentinel") ? (t7 = {
120
+ }, $[6] = t4) : t4 = $[6];
121
+ let t5, t6;
122
+ $[7] === Symbol.for("react.memo_cache_sentinel") ? (t5 = {
133
123
  justifyItems: "flex-start",
134
124
  textWrap: "pretty"
135
- }, t8 = /* @__PURE__ */ jsx(Heading, { children: "Vercel Protection Bypass" }), $[10] = t7, $[11] = t8) : (t7 = $[10], t8 = $[11]);
136
- let t9;
137
- $[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: [
138
- t8,
125
+ }, t6 = /* @__PURE__ */ jsx(Heading, { children: "Vercel Protection Bypass" }), $[7] = t5, $[8] = t6) : (t5 = $[7], t6 = $[8]);
126
+ let t7;
127
+ $[9] !== enabled || $[10] !== loading ? (t7 = /* @__PURE__ */ jsx(Box, { as: "form", action: formAction, sizing: "border", display: "flex", style: t3, children: /* @__PURE__ */ jsx(Stack, { space: 5, children: /* @__PURE__ */ jsx(Card, { padding: 4, style: t4, children: /* @__PURE__ */ jsxs(Stack, { space: 4, style: t5, children: [
128
+ t6,
139
129
  enabled ? /* @__PURE__ */ jsxs(Fragment, { children: [
140
130
  /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { style: {
141
131
  textWrap: "pretty"
@@ -147,25 +137,7 @@ function VercelProtectionBypassTool() {
147
137
  "in order to display protected deployments in its preview iframe for the current Sanity dataset."
148
138
  ] }) }),
149
139
  /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: "You can turn off automatic protection bypass at any time by clicking the button below." }) }),
150
- /* @__PURE__ */ jsx(Button, { mode: "ghost", tone: "critical", icon: /* @__PURE__ */ jsx(TrashIcon, {}), loading: removing, onClick: () => {
151
- dispatch({
152
- type: "remove-secret"
153
- }), disableVercelProtectionBypass(client).then(() => {
154
- pushToast({
155
- status: "warning",
156
- title: "Protection bypass is now disabled"
157
- }), dispatch({
158
- type: "removed-secret"
159
- });
160
- }).catch((reason_0) => {
161
- console.error(reason_0), pushToast({
162
- status: "error",
163
- title: "There was an error when trying to disable protection bypass. See the browser console for more information."
164
- }), dispatch({
165
- type: "failed-remove-secret"
166
- });
167
- });
168
- }, text: "Remove secret" }),
140
+ /* @__PURE__ */ jsx(Button, { mode: "ghost", tone: "critical", icon: /* @__PURE__ */ jsx(TrashIcon, {}), loading, type: "submit", name: "action", value: "remove-secret", text: "Remove secret" }),
169
141
  /* @__PURE__ */ jsx(Text, { children: "Protection bypass remains enabled if this plugin is removed from your Sanity config." })
170
142
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
171
143
  /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { style: {
@@ -177,40 +149,68 @@ function VercelProtectionBypassTool() {
177
149
  "."
178
150
  ] }) }),
179
151
  /* @__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." }) }),
180
- /* @__PURE__ */ jsx(Button, { mode: "ghost", icon: /* @__PURE__ */ jsx(AddIcon, {}), loading: state.status === "loading", onClick: () => {
181
- dispatch({
182
- type: "add-secret"
183
- });
152
+ /* @__PURE__ */ jsx(Button, { mode: "ghost", icon: /* @__PURE__ */ jsx(AddIcon, {}), onClick: () => {
153
+ setIsDialogOpen(!0);
184
154
  }, text: "Add secret" }),
185
155
  /* @__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." })
186
156
  ] })
187
- ] }) }) }) }), $[12] = client, $[13] = enabled, $[14] = pushToast, $[15] = removing, $[16] = state.status, $[17] = t9) : t9 = $[17];
188
- let t10;
189
- $[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({
190
- type: "cancel-add-secret"
191
- }), children: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsx("form", { onSubmit: (event) => {
192
- event.preventDefault(), event.currentTarget.reportValidity();
193
- const secret_1 = new FormData(event.currentTarget).get("secret");
194
- secret_1 && handleEnable(secret_1);
195
- }, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
196
- /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
197
- /* @__PURE__ */ jsx(Text, { as: "label", weight: "semibold", size: 1, children: "Add bypass secret" }),
198
- /* @__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." }),
199
- /* @__PURE__ */ jsx(TextInput, { name: "secret", onFocus: _temp, onBlur: _temp2, minLength: 32, maxLength: 32, autoComplete: "off", autoCapitalize: "off", autoCorrect: "off", spellCheck: "false", disabled: adding })
200
- ] }),
201
- /* @__PURE__ */ jsx(Button, { type: "submit", loading: adding, text: adding ? "Saving\u2026" : "Save", tone: "positive" })
202
- ] }) }) }) }), $[18] = adding, $[19] = handleEnable, $[20] = state.status, $[21] = t10) : t10 = $[21];
203
- let t11;
204
- return $[22] !== t10 || $[23] !== t9 ? (t11 = /* @__PURE__ */ jsxs(Fragment, { children: [
205
- t9,
206
- t10
207
- ] }), $[22] = t10, $[23] = t9, $[24] = t11) : t11 = $[24], t11;
157
+ ] }) }) }) }), $[9] = enabled, $[10] = loading, $[11] = t7) : t7 = $[11];
158
+ const t8 = isDialogOpen ? "visible" : "hidden";
159
+ let t9;
160
+ $[12] === Symbol.for("react.memo_cache_sentinel") ? (t9 = () => setIsDialogOpen(!1), $[12] = t9) : t9 = $[12];
161
+ let t10, t11;
162
+ $[13] === Symbol.for("react.memo_cache_sentinel") ? (t10 = /* @__PURE__ */ jsx(Text, { as: "label", weight: "semibold", size: 1, children: "Add bypass secret" }), t11 = /* @__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." }), $[13] = t10, $[14] = t11) : (t10 = $[13], t11 = $[14]);
163
+ let t12;
164
+ $[15] !== loading ? (t12 = /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
165
+ t10,
166
+ t11,
167
+ /* @__PURE__ */ jsx(TextInput, { name: "secret", onFocus: _temp, onBlur: _temp2, minLength: 32, maxLength: 32, autoComplete: "off", autoCapitalize: "off", autoCorrect: "off", spellCheck: "false", disabled: loading })
168
+ ] }), $[15] = loading, $[16] = t12) : t12 = $[16];
169
+ const t13 = loading ? "Saving\u2026" : "Save";
170
+ let t14;
171
+ $[17] !== loading || $[18] !== t13 ? (t14 = /* @__PURE__ */ jsx(Button, { type: "submit", loading, text: t13, tone: "positive", name: "action", value: "add-secret" }), $[17] = loading, $[18] = t13, $[19] = t14) : t14 = $[19];
172
+ let t15;
173
+ $[20] !== t12 || $[21] !== t14 ? (t15 = /* @__PURE__ */ jsx(Dialog, { animate: !0, id: "add-secret-dialog", onClickOutside: t9, children: /* @__PURE__ */ jsx(Card, { as: "form", action: formAction, padding: 3, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
174
+ t12,
175
+ t14
176
+ ] }) }) }), $[20] = t12, $[21] = t14, $[22] = t15) : t15 = $[22];
177
+ let t16;
178
+ $[23] !== t15 || $[24] !== t8 ? (t16 = /* @__PURE__ */ jsx(Activity, { mode: t8, children: t15 }), $[23] = t15, $[24] = t8, $[25] = t16) : t16 = $[25];
179
+ let t17;
180
+ return $[26] !== t16 || $[27] !== t7 ? (t17 = /* @__PURE__ */ jsxs(Fragment, { children: [
181
+ t7,
182
+ t16
183
+ ] }), $[26] = t16, $[27] = t7, $[28] = t17) : t17 = $[28], t17;
184
+ }
185
+ function _temp2(event_0) {
186
+ event_0.currentTarget.setCustomValidity(event_0.currentTarget.value.length == 32 ? "" : "Secret must be 32 characters long"), event_0.currentTarget.required = !0;
208
187
  }
209
- function _temp2(event_1) {
210
- event_1.currentTarget.setCustomValidity(event_1.currentTarget.value.length == 32 ? "" : "Secret must be 32 characters long"), event_1.currentTarget.required = !0;
188
+ function _temp(event) {
189
+ event.currentTarget.setCustomValidity("");
190
+ }
191
+ function useRefetchOnLiveEvent(client, formState, action) {
192
+ const $ = c(8), [isBackgroundRefetch, startTransition] = useTransition();
193
+ let t0;
194
+ $[0] !== action || $[1] !== formState ? (t0 = (event) => {
195
+ if (event.type === "message" && event.tags.some((tag2) => formState.syncTags.includes(tag2))) {
196
+ const formData = new FormData();
197
+ formData.set("action", "refresh-secret"), formData.set("lastLiveEventId", event.id), startTransition(() => action(formData));
198
+ }
199
+ }, $[0] = action, $[1] = formState, $[2] = t0) : t0 = $[2];
200
+ const handleLiveEvent = useEffectEvent(t0);
201
+ let t1;
202
+ $[3] !== client.live || $[4] !== handleLiveEvent ? (t1 = () => {
203
+ const subscription = client.live.events().subscribe({
204
+ next: handleLiveEvent,
205
+ error: _temp3
206
+ });
207
+ return () => subscription.unsubscribe();
208
+ }, $[3] = client.live, $[4] = handleLiveEvent, $[5] = t1) : t1 = $[5];
209
+ let t2;
210
+ return $[6] !== client ? (t2 = [client], $[6] = client, $[7] = t2) : t2 = $[7], useEffect(t1, t2), isBackgroundRefetch;
211
211
  }
212
- function _temp(event_0) {
213
- event_0.currentTarget.setCustomValidity("");
212
+ function _temp3(reason) {
213
+ return console.error(reason);
214
214
  }
215
215
  export {
216
216
  VercelProtectionBypassTool as default
@@ -1 +1 @@
1
- {"version":3,"file":"VercelProtectionBypassTool.js","sources":["../../src/VercelProtectionBypassTool.tsx"],"sourcesContent":["import {useEffect, useReducer} from 'react'\nimport {useClient, type SanityClient} from 'sanity'\n\nimport {AddIcon, TrashIcon} from '@sanity/icons'\nimport {apiVersion} from '@sanity/preview-url-secret/constants'\nimport {\n vercelProtectionBypassSchemaId as _id,\n vercelProtectionBypassSchemaType as _type,\n tag,\n} from '@sanity/preview-url-secret/constants'\nimport {subscribeToVercelProtectionBypass} from '@sanity/preview-url-secret/toggle-vercel-protection-bypass'\nimport {Box, Button, Card, Dialog, Heading, Stack, Text, TextInput, useToast} from '@sanity/ui'\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\nasync function enableVercelProtectionBypass(client: SanityClient, secret: string): Promise<void> {\n const patch = client.patch(_id).set({secret})\n await client.transaction().createIfNotExists({_id, _type}).patch(patch).commit({tag})\n}\n\nasync function disableVercelProtectionBypass(client: SanityClient): Promise<void> {\n const patch = client.patch(_id).set({secret: null})\n await client.transaction().createIfNotExists({_id, _type}).patch(patch).commit({tag})\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 = subscribeToVercelProtectionBypass(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","enableVercelProtectionBypass","client","secret","patch","_id","set","transaction","createIfNotExists","_type","commit","tag","disableVercelProtectionBypass","VercelProtectionBypassTool","$","_c","t0","Symbol","for","apiVersion","useClient","push","pushToast","useToast","t1","state","dispatch","useReducer","adding","removing","t2","then","title","catch","reason","console","error","handleEnable","t3","t4","unsubscribe","subscribeToVercelProtectionBypass","secret_0","useEffect","enabled","t5","height","alignItems","justifyContent","flexDirection","t6","maxWidth","t7","t8","justifyItems","textWrap","t9","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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"}
1
+ {"version":3,"file":"VercelProtectionBypassTool.js","sources":["../../src/VercelProtectionBypassTool.tsx"],"sourcesContent":["import {\n Activity,\n Suspense,\n use,\n useActionState,\n useEffect,\n useEffectEvent,\n useState,\n useTransition,\n} from 'react'\nimport {useClient, type SanityClient} from 'sanity'\n\nimport type {SyncTag, LiveEvent} from '@sanity/client'\n\nimport {AddIcon, TrashIcon} from '@sanity/icons'\nimport {\n apiVersion,\n vercelProtectionBypassSchemaId as _id,\n vercelProtectionBypassSchemaType as _type,\n tag,\n fetchVercelProtectionBypassSecret,\n} from '@sanity/preview-url-secret/constants'\nimport {\n Box,\n Button,\n Card,\n Dialog,\n Flex,\n Heading,\n Spinner,\n Stack,\n Text,\n TextInput,\n useToast,\n} from '@sanity/ui'\n\nasync function enableVercelProtectionBypass(client: SanityClient, secret: string): Promise<void> {\n const patch = client.patch(_id).set({secret})\n await client.transaction().createIfNotExists({_id, _type}).patch(patch).commit({tag})\n}\n\nasync function disableVercelProtectionBypass(client: SanityClient): Promise<void> {\n const patch = client.patch(_id).set({secret: null})\n await client.transaction().createIfNotExists({_id, _type}).patch(patch).commit({tag})\n}\n\nexport default function VercelProtectionBypassTool(): React.JSX.Element {\n const client = useClient({apiVersion: apiVersion})\n\n async function fetchSecret(lastLiveEventId: string | null): Promise<FormState> {\n const {result, syncTags} = await client.fetch<string | null>(\n fetchVercelProtectionBypassSecret,\n {},\n {\n filterResponse: false,\n lastLiveEventId,\n tag: 'preview-url-secret.fetch-vercel-bypass-protection-secret',\n },\n )\n return {secret: result, syncTags: syncTags ?? []}\n }\n const [initialStatePromise] = useState(() => fetchSecret(null))\n\n return (\n <Suspense\n fallback={\n <Flex\n align=\"center\"\n direction=\"column\"\n height=\"fill\"\n justify=\"center\"\n style={{width: '100%'}}\n >\n <Spinner />\n </Flex>\n }\n >\n <Layout initialStatePromise={initialStatePromise} fetchSecret={fetchSecret} />\n </Suspense>\n )\n}\n\ntype FormAction = 'remove-secret' | 'add-secret' | 'refresh-secret'\ntype FormName = 'action' | 'lastLiveEventId' | 'secret'\ntype FormState = {secret: string | null; syncTags: SyncTag[]}\n\nfunction Layout({\n initialStatePromise,\n fetchSecret,\n}: {\n initialStatePromise: Promise<FormState>\n fetchSecret(lastLiveEventId: string | null): Promise<FormState>\n}) {\n const {push: pushToast} = useToast()\n const [isDialogOpen, setIsDialogOpen] = useState(false)\n const client = useClient({apiVersion})\n\n const action = async (prevState: FormState, formData: FormData): Promise<FormState> => {\n const action = formData.get('action' satisfies FormName) as FormAction\n\n switch (action) {\n case 'remove-secret':\n return disableVercelProtectionBypass(client)\n .then((): FormState => {\n pushToast({\n status: 'warning',\n title: 'Protection bypass is now disabled',\n })\n return {...prevState, secret: null}\n })\n .catch((reason): FormState => {\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 return prevState\n })\n\n case 'add-secret': {\n const secret = formData.get('secret' satisfies FormName) as string\n return enableVercelProtectionBypass(client, secret)\n .then(() => {\n pushToast({\n status: 'success',\n title: 'Protection bypass is now enabled',\n })\n setIsDialogOpen(false)\n return {...prevState, 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 enable protection bypass. See the browser console for more information.',\n })\n return prevState\n })\n }\n case 'refresh-secret':\n return fetchSecret(formData.get('lastLiveEventId' satisfies FormName) as string)\n default:\n throw new Error(`Unknown action: ${action}`)\n }\n }\n\n const [formState, formAction, isPending] = useActionState(action, use(initialStatePromise))\n const isBackgroundRefetch = useRefetchOnLiveEvent(client, formState, formAction)\n\n const loading = isPending && !isBackgroundRefetch\n const enabled = Boolean(formState.secret)\n\n return (\n <>\n <Box\n as=\"form\"\n action={formAction}\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={loading}\n type=\"submit\"\n name={'action' satisfies FormName}\n value={'remove-secret' satisfies FormAction}\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 onClick={() => {\n setIsDialogOpen(true)\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\n <Activity mode={isDialogOpen ? 'visible' : 'hidden'}>\n <Dialog animate id=\"add-secret-dialog\" onClickOutside={() => setIsDialogOpen(false)}>\n <Card as=\"form\" action={formAction} padding={3}>\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' satisfies FormName}\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={loading}\n />\n </Stack>\n <Button\n type=\"submit\"\n loading={loading}\n text={loading ? 'Saving…' : 'Save'}\n tone=\"positive\"\n name={'action' satisfies FormName}\n value={'add-secret' satisfies FormAction}\n />\n </Stack>\n </Card>\n </Dialog>\n </Activity>\n </>\n )\n}\n\ntype isBackgroundRefetch = boolean\nfunction useRefetchOnLiveEvent(\n client: SanityClient,\n formState: FormState,\n action: (formData: FormData) => void,\n): isBackgroundRefetch {\n const [isBackgroundRefetch, startTransition] = useTransition()\n const handleLiveEvent = useEffectEvent((event: LiveEvent) => {\n if (event.type === 'message' && event.tags.some((tag) => formState.syncTags.includes(tag))) {\n const formData = new FormData()\n formData.set('action' satisfies FormName, 'refresh-secret' satisfies FormAction)\n formData.set('lastLiveEventId' satisfies FormName, event.id)\n startTransition(() => action(formData))\n }\n })\n useEffect(() => {\n const subscription = client.live.events().subscribe({\n next: handleLiveEvent,\n // eslint-disable-next-line no-console\n error: (reason) => console.error(reason),\n })\n\n return () => subscription.unsubscribe()\n }, [client])\n return isBackgroundRefetch\n}\n"],"names":["enableVercelProtectionBypass","client","secret","patch","_id","set","transaction","createIfNotExists","_type","commit","tag","disableVercelProtectionBypass","VercelProtectionBypassTool","$","_c","t0","Symbol","for","apiVersion","useClient","t1","lastLiveEventId","result","syncTags","fetch","fetchVercelProtectionBypassSecret","filterResponse","fetchSecret","t2","initialStatePromise","useState","t3","width","t4","Layout","push","pushToast","useToast","isDialogOpen","setIsDialogOpen","prevState","formData","action","get","then","status","title","catch","reason_0","console","error","reason","Error","action_0","formState","formAction","isPending","useActionState","use","isBackgroundRefetch","useRefetchOnLiveEvent","loading","enabled","Boolean","height","alignItems","justifyContent","flexDirection","maxWidth","t5","t6","justifyItems","textWrap","t7","t8","t9","t10","t11","t12","_temp","_temp2","t13","t14","t15","t16","t17","event_0","event","currentTarget","setCustomValidity","value","length","required","startTransition","useTransition","type","tags","some","includes","FormData","id","handleLiveEvent","useEffectEvent","live","subscription","events","subscribe","next","_temp3","unsubscribe","useEffect"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,22 +1,54 @@
1
1
  import { lazy } from "react";
2
- import { definePlugin } from "sanity";
2
+ import { definePlugin, defineType } from "sanity";
3
+ import { LockIcon, CheckmarkCircleIcon, CloseCircleIcon } from "@sanity/icons";
4
+ import { vercelProtectionBypassSchemaType } from "@sanity/preview-url-secret/constants";
3
5
  const id = "vercel-protection-bypass", vercelProtectionBypassTool = definePlugin((options) => {
4
6
  const {
5
- name,
6
- title,
7
- icon,
7
+ name = "vercel-protection-bypass",
8
+ title = "Vercel Protection Bypass",
9
+ icon = LockIcon,
8
10
  ...config
9
11
  } = options || {};
10
12
  return {
11
13
  name: `@sanity/preview-url-secret/${id}`,
12
14
  tools: [{
13
- name: name || "vercel-protection-bypass",
14
- title: title || "Vercel Protection Bypass",
15
+ name,
16
+ title,
15
17
  icon,
16
18
  component: lazy(() => import("./_chunks-es/VercelProtectionBypassTool.js")),
17
19
  options: config,
18
20
  __internalApplicationType: `sanity/${id}`
19
- }]
21
+ }],
22
+ document: {
23
+ actions: (prev, context) => context.schemaType !== vercelProtectionBypassSchemaType ? prev : []
24
+ },
25
+ schema: {
26
+ types: [defineType({
27
+ type: "document",
28
+ icon: LockIcon,
29
+ name: vercelProtectionBypassSchemaType,
30
+ title,
31
+ readOnly: !0,
32
+ fields: [{
33
+ type: "string",
34
+ name: "secret",
35
+ title: "Secret"
36
+ }],
37
+ preview: {
38
+ select: {
39
+ secret: "secret"
40
+ },
41
+ prepare(data) {
42
+ const enabled = data.secret !== null;
43
+ return {
44
+ title: enabled ? "Enabled" : "Disabled",
45
+ subtitle: title,
46
+ media: enabled ? CheckmarkCircleIcon : CloseCircleIcon
47
+ };
48
+ }
49
+ }
50
+ })]
51
+ }
20
52
  };
21
53
  });
22
54
  export {
package/dist/index.js.map CHANGED
@@ -1 +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,CAAAA,YAAY;AACX,QAAM;AAAA,IAACC;AAAAA,IAAMC;AAAAA,IAAOC;AAAAA,IAAM,GAAGC;AAAAA,EAAAA,IAAUJ,WAAW,CAAA;AAClD,SAAO;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,IAAA,CACxC;AAAA,EAAA;AAGP,CACF;"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import {lazy} from 'react'\nimport {definePlugin, defineType} from 'sanity'\n\nimport {CheckmarkCircleIcon, CloseCircleIcon, LockIcon} from '@sanity/icons'\nimport {\n vercelProtectionBypassSchemaId as _id,\n vercelProtectionBypassSchemaType as type,\n} from '@sanity/preview-url-secret/constants'\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 {\n name = 'vercel-protection-bypass',\n title = 'Vercel Protection Bypass',\n icon = LockIcon,\n ...config\n } = options || {}\n return {\n name: `@sanity/preview-url-secret/${id}`,\n tools: [\n {\n name,\n title,\n icon: icon,\n component: lazy(() => import('./VercelProtectionBypassTool')),\n options: config,\n __internalApplicationType: `sanity/${id}`,\n },\n ],\n document: {\n actions: (prev, context) => {\n if (context.schemaType !== type) {\n return prev\n }\n return []\n },\n },\n schema: {\n types: [\n defineType({\n type: 'document',\n icon: LockIcon,\n name: type,\n title,\n readOnly: true,\n fields: [\n {\n type: 'string',\n name: 'secret',\n title: 'Secret',\n },\n ],\n preview: {\n select: {\n secret: 'secret',\n },\n prepare(data) {\n const enabled = data['secret'] !== null\n return {\n title: enabled ? 'Enabled' : 'Disabled',\n subtitle: title,\n media: enabled ? CheckmarkCircleIcon : CloseCircleIcon,\n }\n },\n },\n }),\n ],\n },\n }\n },\n)\n"],"names":["id","vercelProtectionBypassTool","definePlugin","options","name","title","icon","LockIcon","config","tools","component","lazy","__internalApplicationType","document","actions","prev","context","schemaType","type","schema","types","defineType","readOnly","fields","preview","select","secret","prepare","data","enabled","subtitle","media","CheckmarkCircleIcon","CloseCircleIcon"],"mappings":";;;;AASA,MAAMA,KAAK,4BAQEC,6BAA6BC,aACvCC,CAAAA,YAAY;AACX,QAAM;AAAA,IACJC,OAAO;AAAA,IACPC,QAAQ;AAAA,IACRC,OAAOC;AAAAA,IACP,GAAGC;AAAAA,EAAAA,IACDL,WAAW,CAAA;AACf,SAAO;AAAA,IACLC,MAAM,8BAA8BJ,EAAE;AAAA,IACtCS,OAAO,CACL;AAAA,MACEL;AAAAA,MACAC;AAAAA,MACAC;AAAAA,MACAI,WAAWC,KAAK,MAAM,OAAO,4CAA8B,CAAC;AAAA,MAC5DR,SAASK;AAAAA,MACTI,2BAA2B,UAAUZ,EAAE;AAAA,IAAA,CACxC;AAAA,IAEHa,UAAU;AAAA,MACRC,SAASA,CAACC,MAAMC,YACVA,QAAQC,eAAeC,mCAClBH,OAEF,CAAA;AAAA,IAAA;AAAA,IAGXI,QAAQ;AAAA,MACNC,OAAO,CACLC,WAAW;AAAA,QACTH,MAAM;AAAA,QACNZ,MAAMC;AAAAA,QACNH,MAAMc;AAAAA,QACNb;AAAAA,QACAiB,UAAU;AAAA,QACVC,QAAQ,CACN;AAAA,UACEL,MAAM;AAAA,UACNd,MAAM;AAAA,UACNC,OAAO;AAAA,QAAA,CACR;AAAA,QAEHmB,SAAS;AAAA,UACPC,QAAQ;AAAA,YACNC,QAAQ;AAAA,UAAA;AAAA,UAEVC,QAAQC,MAAM;AACZ,kBAAMC,UAAUD,KAAK,WAAc;AACnC,mBAAO;AAAA,cACLvB,OAAOwB,UAAU,YAAY;AAAA,cAC7BC,UAAUzB;AAAAA,cACV0B,OAAOF,UAAUG,sBAAsBC;AAAAA,YAAAA;AAAAA,UAE3C;AAAA,QAAA;AAAA,MACF,CACD,CAAC;AAAA,IAAA;AAAA,EAEN;AAEJ,CACF;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/vercel-protection-bypass",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "homepage": "https://github.com/sanity-io/plugins/tree/main/packages/%40sanity/vercel-protection-bypass#readme",
5
5
  "bugs": {
6
6
  "url": "https://github.com/sanity-io/plugins/issues"
@@ -29,9 +29,6 @@
29
29
  "types": "./dist/index.d.ts",
30
30
  "files": [
31
31
  "dist",
32
- "src",
33
- "!src/**/*.test.ts",
34
- "!src/**/*.test-d.ts",
35
32
  "CHANGELOG.md"
36
33
  ],
37
34
  "dependencies": {
@@ -41,17 +38,19 @@
41
38
  "react-compiler-runtime": "^1.0.0"
42
39
  },
43
40
  "devDependencies": {
41
+ "@sanity/client": "^7.13.0",
44
42
  "@sanity/pkg-utils": "^9.1.1",
45
43
  "@types/react": "^19.2.6",
46
- "@typescript/native-preview": "7.0.0-dev.20251117.1",
44
+ "@typescript/native-preview": "7.0.0-dev.20251118.1",
47
45
  "babel-plugin-react-compiler": "^1.0.0",
48
46
  "react": "^19.2.0",
49
- "sanity": "^4.16.0",
50
- "typescript": "5.9.3"
47
+ "sanity": "^4.17.0",
48
+ "typescript": "5.9.3",
49
+ "@repo/package.config": "0.0.0"
51
50
  },
52
51
  "peerDependencies": {
53
- "react": "^18.3 || ^19",
54
- "sanity": "^3.93.0 || ^4"
52
+ "react": "^19.2",
53
+ "sanity": "^4"
55
54
  },
56
55
  "engines": {
57
56
  "node": ">=20.19 <22 || >=22.12"
@@ -60,7 +59,7 @@
60
59
  "access": "public"
61
60
  },
62
61
  "scripts": {
63
- "typecheck": "(cd ../../.. && tsgo --project packages/@sanity/vercel-protection-bypass/tsconfig.json)",
62
+ "typecheck": "(cd ../../.. && tsgo --project plugins/@sanity/vercel-protection-bypass/tsconfig.json)",
64
63
  "build": "pkg build --strict --check --clean"
65
64
  }
66
65
  }
@@ -1,275 +0,0 @@
1
- import {useEffect, useReducer} from 'react'
2
- import {useClient, type SanityClient} from 'sanity'
3
-
4
- import {AddIcon, TrashIcon} from '@sanity/icons'
5
- import {apiVersion} from '@sanity/preview-url-secret/constants'
6
- import {
7
- vercelProtectionBypassSchemaId as _id,
8
- vercelProtectionBypassSchemaType as _type,
9
- tag,
10
- } from '@sanity/preview-url-secret/constants'
11
- import {subscribeToVercelProtectionBypass} from '@sanity/preview-url-secret/toggle-vercel-protection-bypass'
12
- import {Box, Button, Card, Dialog, Heading, Stack, Text, TextInput, useToast} from '@sanity/ui'
13
-
14
- interface State {
15
- status:
16
- | 'loading'
17
- | 'disabled'
18
- | 'add-secret-dialog'
19
- | 'adding-secret'
20
- | 'enabled'
21
- | 'removing-secret'
22
- }
23
- type Action =
24
- | {type: 'add-secret'}
25
- | {type: 'save-secret'}
26
- | {type: 'cancel-add-secret'}
27
- | {type: 'failed-add-secret'}
28
- | {type: 'saved-secret'}
29
- | {type: 'remove-secret'}
30
- | {type: 'failed-remove-secret'}
31
- | {type: 'removed-secret'}
32
-
33
- function reducer(prevState: State, action: Action): State {
34
- switch (action.type) {
35
- case 'removed-secret':
36
- return {...prevState, status: 'disabled'}
37
- case 'remove-secret':
38
- return {...prevState, status: 'removing-secret'}
39
- case 'saved-secret':
40
- return {...prevState, status: 'enabled'}
41
- case 'save-secret':
42
- return {...prevState, status: 'adding-secret'}
43
- case 'cancel-add-secret':
44
- return {...prevState, status: 'disabled'}
45
- case 'add-secret':
46
- return {...prevState, status: 'add-secret-dialog'}
47
- case 'failed-remove-secret':
48
- return {...prevState, status: 'enabled'}
49
- case 'failed-add-secret':
50
- return {...prevState, status: 'add-secret-dialog'}
51
- default:
52
- return prevState
53
- }
54
- }
55
-
56
- async function enableVercelProtectionBypass(client: SanityClient, secret: string): Promise<void> {
57
- const patch = client.patch(_id).set({secret})
58
- await client.transaction().createIfNotExists({_id, _type}).patch(patch).commit({tag})
59
- }
60
-
61
- async function disableVercelProtectionBypass(client: SanityClient): Promise<void> {
62
- const patch = client.patch(_id).set({secret: null})
63
- await client.transaction().createIfNotExists({_id, _type}).patch(patch).commit({tag})
64
- }
65
-
66
- export default function VercelProtectionBypassTool(): React.JSX.Element {
67
- const client = useClient({apiVersion: apiVersion})
68
- const {push: pushToast} = useToast()
69
- const [state, dispatch] = useReducer(reducer, {status: 'loading'})
70
- const adding = state.status === 'adding-secret'
71
- const removing = state.status === 'removing-secret'
72
-
73
- const handleEnable = (secret: string) => {
74
- dispatch({type: 'save-secret'})
75
- enableVercelProtectionBypass(client, secret)
76
- .then(() => {
77
- dispatch({type: 'saved-secret'})
78
- pushToast({
79
- status: 'success',
80
- title: 'Protection bypass is now enabled',
81
- })
82
- })
83
- .catch((reason) => {
84
- // eslint-disable-next-line no-console
85
- console.error(reason)
86
- pushToast({
87
- status: 'error',
88
- title:
89
- 'There was an error when trying to enable protection bypass. See the browser console for more information.',
90
- })
91
- dispatch({type: 'failed-add-secret'})
92
- })
93
- }
94
-
95
- useEffect(() => {
96
- const unsubscribe = subscribeToVercelProtectionBypass(client, (secret) =>
97
- dispatch({type: secret ? 'saved-secret' : 'removed-secret'}),
98
- )
99
- return () => unsubscribe()
100
- }, [client])
101
-
102
- const enabled = state.status === 'enabled' || removing
103
-
104
- return (
105
- <>
106
- <Box
107
- sizing="border"
108
- display="flex"
109
- style={{
110
- height: '100%',
111
- alignItems: 'center',
112
- justifyContent: 'center',
113
- flexDirection: 'column',
114
- }}
115
- >
116
- <Stack space={5}>
117
- <Card padding={4} style={{maxWidth: 640}}>
118
- <Stack space={4} style={{justifyItems: 'flex-start', textWrap: 'pretty'}}>
119
- <Heading>Vercel Protection Bypass</Heading>
120
- {enabled ? (
121
- <>
122
- <Box>
123
- <Text style={{textWrap: 'pretty'}}>
124
- Sanity Presentation is setup to use{' '}
125
- <a
126
- href="https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation"
127
- target="_blank"
128
- rel="noreferrer"
129
- >
130
- protection bypass for automation
131
- </a>{' '}
132
- in order to display protected deployments in its preview iframe for the
133
- current Sanity dataset.
134
- </Text>
135
- </Box>
136
- <Box>
137
- <Text>
138
- You can turn off automatic protection bypass at any time by clicking the
139
- button below.
140
- </Text>
141
- </Box>
142
- <Button
143
- mode="ghost"
144
- tone="critical"
145
- icon={<TrashIcon />}
146
- loading={removing}
147
- onClick={() => {
148
- dispatch({type: 'remove-secret'})
149
- disableVercelProtectionBypass(client)
150
- .then(() => {
151
- pushToast({
152
- status: 'warning',
153
- title: 'Protection bypass is now disabled',
154
- })
155
- dispatch({type: 'removed-secret'})
156
- })
157
- .catch((reason) => {
158
- // eslint-disable-next-line no-console
159
- console.error(reason)
160
- pushToast({
161
- status: 'error',
162
- title:
163
- 'There was an error when trying to disable protection bypass. See the browser console for more information.',
164
- })
165
- dispatch({type: 'failed-remove-secret'})
166
- })
167
- }}
168
- text="Remove secret"
169
- />
170
- <Text>
171
- Protection bypass remains enabled if this plugin is removed from your Sanity
172
- config.
173
- </Text>
174
- </>
175
- ) : (
176
- <>
177
- <Box>
178
- <Text style={{textWrap: 'pretty'}}>
179
- Follow the instructions on{' '}
180
- <a
181
- href="https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation"
182
- target="_blank"
183
- rel="noreferrer"
184
- >
185
- how to enable protection bypass for automation
186
- </a>
187
- .
188
- </Text>
189
- </Box>
190
- <Box>
191
- <Text>
192
- This will setup a secret that Vercel exposes as an environment variable called
193
- VERCEL_AUTOMATION_BYPASS_SECRET, its value is the secret you need.
194
- </Text>
195
- </Box>
196
- <Button
197
- mode="ghost"
198
- icon={<AddIcon />}
199
- loading={state.status === 'loading'}
200
- onClick={() => {
201
- dispatch({type: 'add-secret'})
202
- }}
203
- text="Add secret"
204
- />
205
- <Text>
206
- If you&apos;re using Sanity Presentation Tool with multiple protected
207
- deployments ensure that they have the same secret set, as this tool will set a
208
- secret that is shared in your dataset with all instances of Presentation Tool.
209
- </Text>
210
- </>
211
- )}
212
- </Stack>
213
- </Card>
214
- </Stack>
215
- </Box>
216
- {(state.status === 'add-secret-dialog' || state.status === 'adding-secret') && (
217
- <Dialog
218
- animate
219
- id="add-secret-dialog"
220
- onClickOutside={() => dispatch({type: 'cancel-add-secret'})}
221
- >
222
- <Card padding={3}>
223
- <form
224
- onSubmit={(event) => {
225
- event.preventDefault()
226
- event.currentTarget.reportValidity()
227
- const formData = new FormData(event.currentTarget)
228
- const secret = formData.get('secret') as string
229
- if (secret) handleEnable(secret)
230
- }}
231
- >
232
- <Stack space={3}>
233
- <Stack space={2}>
234
- <Text as="label" weight="semibold" size={1}>
235
- Add bypass secret
236
- </Text>
237
- <Text muted size={1}>
238
- {`Make sure it's the same secret the Vercel deployment is using that's loaded in the preview iframe.`}
239
- </Text>
240
- <TextInput
241
- name="secret"
242
- onFocus={(event) => {
243
- event.currentTarget.setCustomValidity('')
244
- }}
245
- onBlur={(event) => {
246
- event.currentTarget.setCustomValidity(
247
- event.currentTarget.value.length == 32
248
- ? ''
249
- : 'Secret must be 32 characters long',
250
- )
251
- event.currentTarget.required = true
252
- }}
253
- minLength={32}
254
- maxLength={32}
255
- autoComplete="off"
256
- autoCapitalize="off"
257
- autoCorrect="off"
258
- spellCheck="false"
259
- disabled={adding}
260
- />
261
- </Stack>
262
- <Button
263
- type="submit"
264
- loading={adding}
265
- text={adding ? 'Saving…' : 'Save'}
266
- tone="positive"
267
- />
268
- </Stack>
269
- </form>
270
- </Card>
271
- </Dialog>
272
- )}
273
- </>
274
- )
275
- }
package/src/index.ts DELETED
@@ -1,29 +0,0 @@
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
- )