@sanity/vercel-protection-bypass 3.0.0 → 3.1.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,15 @@
1
1
  # @sanity/vercel-protection-bypass
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`d090d93`](https://github.com/sanity-io/plugins/commit/d090d939e29a2aa46ccf1e1f18a63eb383630bdd) Thanks [@stipsan](https://github.com/stipsan)! - Add schema type for debugging
8
+
9
+ ### Patch Changes
10
+
11
+ - [`4f82b31`](https://github.com/sanity-io/plugins/commit/4f82b3120b3006821a74f444589ac3e752475c4e) Thanks [@stipsan](https://github.com/stipsan)! - Stop publishing src folder to npm
12
+
3
13
  ## 3.0.0
4
14
 
5
15
  ### Major Changes
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": "3.1.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": {
@@ -43,11 +40,12 @@
43
40
  "devDependencies": {
44
41
  "@sanity/pkg-utils": "^9.1.1",
45
42
  "@types/react": "^19.2.6",
46
- "@typescript/native-preview": "7.0.0-dev.20251117.1",
43
+ "@typescript/native-preview": "7.0.0-dev.20251118.1",
47
44
  "babel-plugin-react-compiler": "^1.0.0",
48
45
  "react": "^19.2.0",
49
- "sanity": "^4.16.0",
50
- "typescript": "5.9.3"
46
+ "sanity": "^4.17.0",
47
+ "typescript": "5.9.3",
48
+ "@repo/package.config": "0.0.0"
51
49
  },
52
50
  "peerDependencies": {
53
51
  "react": "^18.3 || ^19",
@@ -60,7 +58,7 @@
60
58
  "access": "public"
61
59
  },
62
60
  "scripts": {
63
- "typecheck": "(cd ../../.. && tsgo --project packages/@sanity/vercel-protection-bypass/tsconfig.json)",
61
+ "typecheck": "(cd ../../.. && tsgo --project plugins/@sanity/vercel-protection-bypass/tsconfig.json)",
64
62
  "build": "pkg build --strict --check --clean"
65
63
  }
66
64
  }
@@ -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
- )