@sanity/vercel-protection-bypass

5.0.135.0.14
dist/_chunks-es/VercelProtectionBypassTool.js
+dist/_chunks-es/VercelProtectionBypassTool.jsNew file
+276
Index: package/dist/_chunks-es/VercelProtectionBypassTool.js
===================================================================
--- package/dist/_chunks-es/VercelProtectionBypassTool.js
+++ package/dist/_chunks-es/VercelProtectionBypassTool.js
@@ -0,0 +1,276 @@
+import { apiVersion, fetchVercelProtectionBypassSecret, tag, vercelProtectionBypassSchemaId, vercelProtectionBypassSchemaType } from "@sanity/preview-url-secret/constants";
+import { Activity, Suspense, use, useActionState, useEffect, useEffectEvent, useState, useTransition } from "react";
+import { useClient } from "sanity";
+import { c } from "react/compiler-runtime";
+import { AddIcon } from "@sanity/icons/Add";
+import { TrashIcon } from "@sanity/icons/Trash";
+import { Box, Button, Card, Dialog, Flex, Heading, Spinner, Stack, Text, TextInput, useToast } from "@sanity/ui";
+import { Fragment, jsx, jsxs } from "react/jsx-runtime";
+async function enableVercelProtectionBypass(client, secret) {
+	let patch = client.patch(vercelProtectionBypassSchemaId).set({ secret });
+	await client.transaction().createIfNotExists({
+		_id: vercelProtectionBypassSchemaId,
+		_type: vercelProtectionBypassSchemaType
+	}).patch(patch).commit({ tag });
+}
+async function disableVercelProtectionBypass(client) {
+	let patch = client.patch(vercelProtectionBypassSchemaId).set({ secret: null });
+	await client.transaction().createIfNotExists({
+		_id: vercelProtectionBypassSchemaId,
+		_type: vercelProtectionBypassSchemaType
+	}).patch(patch).commit({ tag });
+}
+function VercelProtectionBypassTool() {
+	let $ = c(9), t0;
+	$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = { apiVersion }, $[0] = t0) : t0 = $[0];
+	let client = useClient(t0), t1;
+	$[1] === client ? t1 = $[2] : (t1 = async function(lastLiveEventId) {
+		let { result, syncTags } = await client.fetch(fetchVercelProtectionBypassSecret, {}, {
+			filterResponse: !1,
+			lastLiveEventId: typeof lastLiveEventId == "string" ? lastLiveEventId : null,
+			tag: "preview-url-secret.fetch-vercel-bypass-protection-secret"
+		});
+		return {
+			secret: result,
+			syncTags: syncTags ?? []
+		};
+	}, $[1] = client, $[2] = t1);
+	let fetchSecret = t1, t2;
+	$[3] === fetchSecret ? t2 = $[4] : (t2 = () => fetchSecret(null), $[3] = fetchSecret, $[4] = t2);
+	let [initialStatePromise] = useState(t2), t3;
+	$[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(Flex, {
+		align: "center",
+		direction: "column",
+		height: "fill",
+		justify: "center",
+		style: { width: "100%" },
+		children: /* @__PURE__ */ jsx(Spinner, {})
+	}), $[5] = t3) : t3 = $[5];
+	let t4;
+	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;
+}
+function Layout(t0) {
+	let $ = c(29), { initialStatePromise, fetchSecret } = t0, { push: pushToast } = useToast(), [isDialogOpen, setIsDialogOpen] = useState(!1), t1;
+	$[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = { apiVersion }, $[0] = t1) : t1 = $[0];
+	let client = useClient(t1), t2;
+	$[1] !== client || $[2] !== fetchSecret || $[3] !== pushToast ? (t2 = async (prevState, formData) => {
+		let action = formData.get("action");
+		if (typeof action != "string") throw Error("Action is not a string");
+		switch (action) {
+			case "remove-secret": return disableVercelProtectionBypass(client).then(() => (pushToast({
+				status: "warning",
+				title: "Protection bypass is now disabled"
+			}), {
+				...prevState,
+				secret: null
+			})).catch((reason_0) => (console.error(reason_0), pushToast({
+				status: "error",
+				title: "There was an error when trying to disable protection bypass. See the browser console for more information."
+			}), prevState));
+			case "add-secret": {
+				let secret = formData.get("secret");
+				if (typeof secret != "string") throw Error("Secret is not a string");
+				return enableVercelProtectionBypass(client, secret).then(() => (pushToast({
+					status: "success",
+					title: "Protection bypass is now enabled"
+				}), setIsDialogOpen(!1), {
+					...prevState,
+					secret
+				})).catch((reason) => (console.error(reason), pushToast({
+					status: "error",
+					title: "There was an error when trying to enable protection bypass. See the browser console for more information."
+				}), prevState));
+			}
+			case "refresh-secret": return fetchSecret(formData.get("lastLiveEventId"));
+			default: throw Error(`Unknown action: ${action}`);
+		}
+	}, $[1] = client, $[2] = fetchSecret, $[3] = pushToast, $[4] = t2) : t2 = $[4];
+	let [formState, formAction, isPending] = useActionState(t2, use(initialStatePromise)), isBackgroundRefetch = useRefetchOnLiveEvent(client, formState, formAction), loading = isPending && !isBackgroundRefetch, enabled = !!formState.secret, t3;
+	$[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = {
+		height: "100%",
+		alignItems: "center",
+		justifyContent: "center",
+		flexDirection: "column"
+	}, $[5] = t3) : t3 = $[5];
+	let t4;
+	$[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = { maxWidth: 640 }, $[6] = t4) : t4 = $[6];
+	let t5, t6;
+	$[7] === Symbol.for("react.memo_cache_sentinel") ? (t5 = {
+		justifyItems: "flex-start",
+		textWrap: "pretty"
+	}, t6 = /* @__PURE__ */ jsx(Heading, { children: "Vercel Protection Bypass" }), $[7] = t5, $[8] = t6) : (t5 = $[7], t6 = $[8]);
+	let t7;
+	$[9] !== enabled || $[10] !== loading ? (t7 = /* @__PURE__ */ jsx(Box, {
+		as: "form",
+		action: formAction,
+		sizing: "border",
+		display: "flex",
+		style: t3,
+		children: /* @__PURE__ */ jsx(Stack, {
+			gap: 5,
+			children: /* @__PURE__ */ jsx(Card, {
+				padding: 4,
+				style: t4,
+				children: /* @__PURE__ */ jsxs(Stack, {
+					gap: 4,
+					style: t5,
+					children: [t6, enabled ? /* @__PURE__ */ jsxs(Fragment, { children: [
+						/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, {
+							style: { textWrap: "pretty" },
+							children: [
+								"Sanity Presentation is setup to use",
+								" ",
+								/* @__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"
+								}),
+								" ",
+								"in order to display protected deployments in its preview iframe for the current Sanity dataset."
+							]
+						}) }),
+						/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: "You can turn off automatic protection bypass at any time by clicking the button below." }) }),
+						/* @__PURE__ */ jsx(Button, {
+							mode: "ghost",
+							tone: "critical",
+							icon: /* @__PURE__ */ jsx(TrashIcon, {}),
+							loading,
+							type: "submit",
+							name: "action",
+							value: "remove-secret",
+							text: "Remove secret"
+						}),
+						/* @__PURE__ */ jsx(Text, { children: "Protection bypass remains enabled if this plugin is removed from your Sanity config." })
+					] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
+						/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, {
+							style: { textWrap: "pretty" },
+							children: [
+								"Follow the instructions on",
+								" ",
+								/* @__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"
+								}),
+								"."
+							]
+						}) }),
+						/* @__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." }) }),
+						/* @__PURE__ */ jsx(Button, {
+							mode: "ghost",
+							icon: /* @__PURE__ */ jsx(AddIcon, {}),
+							onClick: () => {
+								setIsDialogOpen(!0);
+							},
+							text: "Add secret"
+						}),
+						/* @__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." })
+					] })]
+				})
+			})
+		})
+	}), $[9] = enabled, $[10] = loading, $[11] = t7) : t7 = $[11];
+	let t8 = isDialogOpen ? "visible" : "hidden", t9;
+	$[12] === Symbol.for("react.memo_cache_sentinel") ? (t9 = () => setIsDialogOpen(!1), $[12] = t9) : t9 = $[12];
+	let t10, t11;
+	$[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]);
+	let t12;
+	$[15] === loading ? t12 = $[16] : (t12 = /* @__PURE__ */ jsxs(Stack, {
+		gap: 2,
+		children: [
+			t10,
+			t11,
+			/* @__PURE__ */ jsx(TextInput, {
+				name: "secret",
+				onFocus: _temp,
+				onBlur: _temp2,
+				minLength: 32,
+				maxLength: 32,
+				autoComplete: "off",
+				autoCapitalize: "off",
+				autoCorrect: "off",
+				spellCheck: "false",
+				disabled: loading
+			})
+		]
+	}), $[15] = loading, $[16] = t12);
+	let t13 = loading ? "Saving…" : "Save", t14;
+	$[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];
+	let t15;
+	$[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, {
+				gap: 3,
+				children: [t12, t14]
+			})
+		})
+	}), $[20] = t12, $[21] = t14, $[22] = t15) : t15 = $[22];
+	let t16;
+	$[23] !== t15 || $[24] !== t8 ? (t16 = /* @__PURE__ */ jsx(Activity, {
+		mode: t8,
+		children: t15
+	}), $[23] = t15, $[24] = t8, $[25] = t16) : t16 = $[25];
+	let t17;
+	return $[26] !== t16 || $[27] !== t7 ? (t17 = /* @__PURE__ */ jsxs(Fragment, { children: [t7, t16] }), $[26] = t16, $[27] = t7, $[28] = t17) : t17 = $[28], t17;
+}
+function _temp2(event_0) {
+	event_0.currentTarget.setCustomValidity(event_0.currentTarget.value.length == 32 ? "" : "Secret must be 32 characters long"), event_0.currentTarget.required = !0;
+}
+function _temp(event) {
+	event.currentTarget.setCustomValidity("");
+}
+function useRefetchOnLiveEvent(client, formState, action) {
+	let $ = c(8), [isBackgroundRefetch, startTransition] = useTransition(), t0;
+	$[0] !== action || $[1] !== formState ? (t0 = (event) => {
+		if (event.type === "message" && event.tags.some((tag) => formState.syncTags.includes(tag))) {
+			let formData = new FormData();
+			formData.set("action", "refresh-secret"), formData.set("lastLiveEventId", event.id), startTransition(() => action(formData));
+		}
+	}, $[0] = action, $[1] = formState, $[2] = t0) : t0 = $[2];
+	let handleLiveEvent = useEffectEvent(t0), t1;
+	$[3] !== client.live || $[4] !== handleLiveEvent ? (t1 = () => {
+		let subscription = client.live.events().subscribe({
+			next: handleLiveEvent,
+			error: _temp3
+		});
+		return () => subscription.unsubscribe();
+	}, $[3] = client.live, $[4] = handleLiveEvent, $[5] = t1) : t1 = $[5];
+	let t2;
+	return $[6] === client ? t2 = $[7] : (t2 = [client], $[6] = client, $[7] = t2), useEffect(t1, t2), isBackgroundRefetch;
+}
+function _temp3(reason) {
+	return console.error(reason);
+}
+export { VercelProtectionBypassTool as default };
+
+//# sourceMappingURL=VercelProtectionBypassTool.js.map
\ No newline at end of file