@liiift-studio/deploy-vercel-from-sanity 1.2.1 → 1.3.1

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/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // src/index.ts
1
+ // src/index.tsx
2
2
  import { definePlugin } from "sanity";
3
3
 
4
4
  // src/icons.tsx
@@ -60,7 +60,28 @@ var WarningOutlineIcon = resolveIcon("WarningOutlineIcon", "warning-outline");
60
60
 
61
61
  // src/components/DeployTool.tsx
62
62
  import { useState as useState8, useEffect as useEffect5, useCallback as useCallback7 } from "react";
63
- import { useClient as useClient3 } from "sanity";
63
+ import { useClient as useClient4 } from "sanity";
64
+
65
+ // src/config.tsx
66
+ import { createContext, useContext } from "react";
67
+ import { jsx as jsx2 } from "react/jsx-runtime";
68
+ var DEFAULTS = { mode: "direct" };
69
+ var ConfigContext = createContext(DEFAULTS);
70
+ function resolveConfig(options) {
71
+ const config = options ?? {};
72
+ return {
73
+ mode: config.mode ?? "direct",
74
+ // Trailing slashes would double up when request paths are appended.
75
+ proxyUrl: config.proxyUrl?.replace(/\/+$/, ""),
76
+ statusKey: config.statusKey
77
+ };
78
+ }
79
+ function ConfigProvider({ value, children }) {
80
+ return /* @__PURE__ */ jsx2(ConfigContext.Provider, { value, children });
81
+ }
82
+ function usePluginConfig() {
83
+ return useContext(ConfigContext);
84
+ }
64
85
 
65
86
  // src/components/DeployItem.tsx
66
87
  import { useState as useState5, useEffect as useEffect4, useCallback as useCallback4, useRef as useRef2 } from "react";
@@ -68,7 +89,7 @@ import { flushSync } from "react-dom";
68
89
 
69
90
  // src/compat/primitives.tsx
70
91
  import { createElement, forwardRef as forwardRef2 } from "react";
71
- import { jsx as jsx2 } from "react/jsx-runtime";
92
+ import { jsx as jsx3 } from "react/jsx-runtime";
72
93
  function domFallback(tag) {
73
94
  const Fallback = forwardRef2(function SanityUiFallback(props, ref) {
74
95
  const { children, style, id, className, onClick, href, title, as, ...rest } = props;
@@ -126,12 +147,12 @@ var Dialog = primitive("Dialog", "div");
126
147
  var SanityStack = primitive("Stack", "div");
127
148
  function Stack({ space, children, ...rest }) {
128
149
  const spacing = space === void 0 ? {} : STACK_USES_GAP ? { gap: space } : { space };
129
- return /* @__PURE__ */ jsx2(SanityStack, { ...rest, ...spacing, children });
150
+ return /* @__PURE__ */ jsx3(SanityStack, { ...rest, ...spacing, children });
130
151
  }
131
152
 
132
153
  // src/compat/toast.tsx
133
154
  import { useCallback, useEffect, useState } from "react";
134
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
155
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
135
156
  var LOCAL_TOAST_MS = 6e3;
136
157
  var MAX_VISIBLE_TOASTS = 4;
137
158
  var TOAST_Z_INDEX = 1e6;
@@ -207,7 +228,7 @@ function ToastViewport() {
207
228
  }
208
229
  }, []);
209
230
  if (installedUseToast) return null;
210
- return /* @__PURE__ */ jsx3(
231
+ return /* @__PURE__ */ jsx4(
211
232
  Box,
212
233
  {
213
234
  role: "log",
@@ -220,7 +241,7 @@ function ToastViewport() {
220
241
  width: "min(360px, calc(100vw - 32px))",
221
242
  pointerEvents: "none"
222
243
  },
223
- children: /* @__PURE__ */ jsx3(Stack, { space: 2, children: toasts.map((toast) => /* @__PURE__ */ jsx3(
244
+ children: /* @__PURE__ */ jsx4(Stack, { space: 2, children: toasts.map((toast) => /* @__PURE__ */ jsx4(
224
245
  Card,
225
246
  {
226
247
  padding: 3,
@@ -234,10 +255,10 @@ function ToastViewport() {
234
255
  onBlurCapture: (e) => resume(toast, e.currentTarget),
235
256
  children: /* @__PURE__ */ jsxs(Flex, { align: "flex-start", gap: 3, children: [
236
257
  /* @__PURE__ */ jsxs(Stack, { space: 2, flex: 1, children: [
237
- toast.title && /* @__PURE__ */ jsx3(Text, { size: 1, weight: "semibold", children: toast.title }),
238
- toast.description && /* @__PURE__ */ jsx3(Text, { size: 1, muted: true, children: toast.description })
258
+ toast.title && /* @__PURE__ */ jsx4(Text, { size: 1, weight: "semibold", children: toast.title }),
259
+ toast.description && /* @__PURE__ */ jsx4(Text, { size: 1, muted: true, children: toast.description })
239
260
  ] }),
240
- /* @__PURE__ */ jsx3(
261
+ /* @__PURE__ */ jsx4(
241
262
  Button,
242
263
  {
243
264
  mode: "bleed",
@@ -258,13 +279,13 @@ function ToastViewport() {
258
279
 
259
280
  // src/compat/tooltip.tsx
260
281
  import { cloneElement, isValidElement, useId, useState as useState2 } from "react";
261
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
282
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
262
283
  var InstalledTooltip = resolveComponent(UI, "Tooltip");
263
284
  function Tooltip({ text, children }) {
264
285
  const id = useId();
265
286
  const [visible, setVisible] = useState2(false);
266
287
  if (InstalledTooltip) {
267
- return /* @__PURE__ */ jsx4(InstalledTooltip, { content: /* @__PURE__ */ jsx4(Box, { padding: 2, children: /* @__PURE__ */ jsx4(Text, { size: 1, children: text }) }), portal: true, children });
288
+ return /* @__PURE__ */ jsx5(InstalledTooltip, { content: /* @__PURE__ */ jsx5(Box, { padding: 2, children: /* @__PURE__ */ jsx5(Text, { size: 1, children: text }) }), portal: true, children });
268
289
  }
269
290
  const described = visible && isValidElement(children) ? cloneElement(children, { "aria-describedby": id }) : children;
270
291
  return /* @__PURE__ */ jsxs2(
@@ -283,7 +304,7 @@ function Tooltip({ text, children }) {
283
304
  },
284
305
  children: [
285
306
  described,
286
- visible && /* @__PURE__ */ jsx4(
307
+ visible && /* @__PURE__ */ jsx5(
287
308
  "span",
288
309
  {
289
310
  id,
@@ -299,7 +320,7 @@ function Tooltip({ text, children }) {
299
320
  whiteSpace: "nowrap",
300
321
  zIndex: 1e3
301
322
  },
302
- children: /* @__PURE__ */ jsx4(Card, { radius: 2, shadow: 2, padding: 2, children: /* @__PURE__ */ jsx4(Text, { size: 1, children: text }) })
323
+ children: /* @__PURE__ */ jsx5(Card, { radius: 2, shadow: 2, padding: 2, children: /* @__PURE__ */ jsx5(Text, { size: 1, children: text }) })
303
324
  }
304
325
  )
305
326
  ]
@@ -309,7 +330,7 @@ function Tooltip({ text, children }) {
309
330
 
310
331
  // src/compat/menu.tsx
311
332
  import { useCallback as useCallback2, useEffect as useEffect2, useId as useId2, useRef, useState as useState3 } from "react";
312
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
333
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
313
334
  var InstalledMenuButton = resolveComponent(UI, "MenuButton");
314
335
  var InstalledMenu = resolveComponent(UI, "Menu");
315
336
  var InstalledMenuItem = resolveComponent(UI, "MenuItem");
@@ -354,13 +375,13 @@ function ActionMenu({ id, label, items, buttonIcon }) {
354
375
  }, [close]);
355
376
  if (INSTALLED_MENU) {
356
377
  const { MenuButton, Menu, MenuItem } = INSTALLED_MENU;
357
- return /* @__PURE__ */ jsx5(
378
+ return /* @__PURE__ */ jsx6(
358
379
  MenuButton,
359
380
  {
360
381
  id,
361
- button: /* @__PURE__ */ jsx5(Button, { mode: "ghost", icon: buttonIcon, padding: 2, "aria-label": label }),
382
+ button: /* @__PURE__ */ jsx6(Button, { mode: "ghost", icon: buttonIcon, padding: 2, "aria-label": label }),
362
383
  popover: { placement: "bottom-end" },
363
- menu: /* @__PURE__ */ jsx5(Menu, { children: items.map((item, i) => /* @__PURE__ */ jsx5(
384
+ menu: /* @__PURE__ */ jsx6(Menu, { children: items.map((item, i) => /* @__PURE__ */ jsx6(
364
385
  MenuItem,
365
386
  {
366
387
  text: item.text,
@@ -428,7 +449,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
428
449
  }
429
450
  };
430
451
  return /* @__PURE__ */ jsxs3("div", { ref: wrapRef, style: { position: "relative" }, children: [
431
- /* @__PURE__ */ jsx5(
452
+ /* @__PURE__ */ jsx6(
432
453
  Button,
433
454
  {
434
455
  ref: triggerRef,
@@ -444,7 +465,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
444
465
  onKeyDown: onTriggerKeyDown
445
466
  }
446
467
  ),
447
- open && /* @__PURE__ */ jsx5(
468
+ open && /* @__PURE__ */ jsx6(
448
469
  Card,
449
470
  {
450
471
  id: menuId,
@@ -455,13 +476,13 @@ function ActionMenu({ id, label, items, buttonIcon }) {
455
476
  "aria-labelledby": id,
456
477
  onKeyDown: onMenuKeyDown,
457
478
  style: { position: "absolute", top: "100%", right: 0, marginTop: 4, zIndex: 1e3, minWidth: 200 },
458
- children: /* @__PURE__ */ jsx5(Stack, { space: 1, role: "none", children: shownItems.map((item, i) => {
479
+ children: /* @__PURE__ */ jsx6(Stack, { space: 1, role: "none", children: shownItems.map((item, i) => {
459
480
  const Icon = item.icon;
460
481
  const row = /* @__PURE__ */ jsxs3(Flex, { align: "center", gap: 2, paddingX: 2, paddingY: 2, children: [
461
- /* @__PURE__ */ jsx5(Icon, { width: "1em", height: "1em", "aria-hidden": "true" }),
462
- /* @__PURE__ */ jsx5(Text, { size: 1, children: item.text })
482
+ /* @__PURE__ */ jsx6(Icon, { width: "1em", height: "1em", "aria-hidden": "true" }),
483
+ /* @__PURE__ */ jsx6(Text, { size: 1, children: item.text })
463
484
  ] });
464
- const content = item.tone === "critical" ? /* @__PURE__ */ jsx5(Card, { tone: "critical", radius: 1, children: row }) : row;
485
+ const content = item.tone === "critical" ? /* @__PURE__ */ jsx6(Card, { tone: "critical", radius: 1, children: row }) : row;
465
486
  const shared = {
466
487
  role: "menuitem",
467
488
  // Roving tabindex — the menu is one tab stop, arrows move within it.
@@ -486,7 +507,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
486
507
  outlineOffset: -2
487
508
  }
488
509
  };
489
- return item.href ? /* @__PURE__ */ jsx5(
510
+ return item.href ? /* @__PURE__ */ jsx6(
490
511
  "a",
491
512
  {
492
513
  ...shared,
@@ -500,7 +521,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
500
521
  children: content
501
522
  },
502
523
  itemKey(item, i)
503
- ) : /* @__PURE__ */ jsx5(
524
+ ) : /* @__PURE__ */ jsx6(
504
525
  "div",
505
526
  {
506
527
  ...shared,
@@ -516,7 +537,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
516
537
  }
517
538
 
518
539
  // src/compat/code.tsx
519
- import { jsx as jsx6 } from "react/jsx-runtime";
540
+ import { jsx as jsx7 } from "react/jsx-runtime";
520
541
  var InstalledCode = resolveComponent(UI, "Code");
521
542
  var FALLBACK_CODE_STYLE = {
522
543
  display: "block",
@@ -526,8 +547,8 @@ var FALLBACK_CODE_STYLE = {
526
547
  margin: 0
527
548
  };
528
549
  function Code({ style, children }) {
529
- if (InstalledCode) return /* @__PURE__ */ jsx6(InstalledCode, { size: 1, style, children });
530
- return /* @__PURE__ */ jsx6("code", { style: { ...FALLBACK_CODE_STYLE, ...style }, children });
550
+ if (InstalledCode) return /* @__PURE__ */ jsx7(InstalledCode, { size: 1, style, children });
551
+ return /* @__PURE__ */ jsx7("code", { style: { ...FALLBACK_CODE_STYLE, ...style }, children });
531
552
  }
532
553
 
533
554
  // src/lib/api.ts
@@ -543,7 +564,7 @@ async function vercelFetch(path, token, init) {
543
564
  }
544
565
  });
545
566
  if (!res.ok) {
546
- const hint = res.status === 401 ? " \u2014 token is invalid or expired. Reconnect your API token." : res.status === 403 ? " \u2014 token lacks the required permissions. Ensure it has Full Account scope." : res.status === 404 ? " \u2014 resource not found. Check the deploy hook URL and team ID." : res.status === 429 ? " \u2014 rate limit reached. Wait a moment and try again." : res.status >= 500 ? " \u2014 Vercel is experiencing issues. Try again shortly." : "";
567
+ const hint = res.status === 401 ? " \u2014 token is invalid or expired. Reconnect your API token." : res.status === 403 ? " \u2014 token lacks the required permissions. Scope it to the team that owns the project, and set the target's Team ID." : res.status === 404 ? " \u2014 resource not found. Check the deploy hook URL and team ID." : res.status === 429 ? " \u2014 rate limit reached. Wait a moment and try again." : res.status >= 500 ? " \u2014 Vercel is experiencing issues. Try again shortly." : "";
547
568
  throw new Error(`Vercel API ${res.status}${hint}`);
548
569
  }
549
570
  return res.json();
@@ -582,15 +603,75 @@ async function getDeploymentEvents(opts) {
582
603
  const params = new URLSearchParams({ limit: "100", direction: "backward" });
583
604
  if (opts.teamId) params.set("teamId", opts.teamId);
584
605
  const raw = await vercelFetch(
585
- `/v2/deployments/${opts.deploymentId}/events?${params}`,
606
+ `/v2/deployments/${encodeURIComponent(opts.deploymentId)}/events?${params}`,
586
607
  opts.token
587
608
  );
588
609
  const events = Array.isArray(raw) ? raw : raw.events ?? [];
589
610
  return events.filter((e) => e.text?.trim());
590
611
  }
591
612
 
613
+ // src/lib/transport.ts
614
+ async function proxyFetch(url, statusKey, init) {
615
+ const res = await fetch(url, {
616
+ ...init,
617
+ headers: {
618
+ "Content-Type": "application/json",
619
+ ...statusKey ? { "x-deploy-status-key": statusKey } : {},
620
+ ...init?.headers
621
+ }
622
+ });
623
+ if (!res.ok) {
624
+ const hint = res.status === 401 ? " \u2014 the proxy rejected the status key. Check `statusKey` matches the proxy." : res.status === 404 ? " \u2014 the proxy has no target with that key. Check `proxyKey` matches the proxy configuration." : res.status >= 500 ? " \u2014 the deploy proxy is failing. Check its logs." : "";
625
+ throw new Error(`Deploy proxy ${res.status}${hint}`);
626
+ }
627
+ return res.json();
628
+ }
629
+ async function fetchDeployments(transport, target, limit) {
630
+ if (transport.mode === "direct") {
631
+ if (!target.projectId || !target.hookId) return [];
632
+ return listDeployments({
633
+ projectId: target.projectId,
634
+ hookId: target.hookId,
635
+ token: transport.token,
636
+ teamId: target.teamId,
637
+ limit
638
+ });
639
+ }
640
+ const params = new URLSearchParams({ key: target.proxyKey ?? "" });
641
+ if (limit) params.set("limit", String(limit));
642
+ const data = await proxyFetch(
643
+ `${transport.proxyUrl}/deployments?${params}`,
644
+ transport.statusKey
645
+ );
646
+ return data.deployments ?? [];
647
+ }
648
+ async function cancelDeploy(transport, target, deploymentId) {
649
+ if (transport.mode === "direct") {
650
+ return cancelDeployment({ deploymentId, token: transport.token, teamId: target.teamId });
651
+ }
652
+ await proxyFetch(`${transport.proxyUrl}/cancel`, transport.statusKey, {
653
+ method: "POST",
654
+ body: JSON.stringify({ key: target.proxyKey, deploymentId })
655
+ });
656
+ }
657
+ async function fetchDeploymentEvents(transport, target, deploymentId) {
658
+ if (transport.mode === "direct") {
659
+ return getDeploymentEvents({ deploymentId, token: transport.token, teamId: target.teamId });
660
+ }
661
+ const params = new URLSearchParams({ key: target.proxyKey ?? "", deploymentId });
662
+ const data = await proxyFetch(
663
+ `${transport.proxyUrl}/events?${params}`,
664
+ transport.statusKey
665
+ );
666
+ return data.events ?? [];
667
+ }
668
+
669
+ // src/components/DeployItem.tsx
670
+ import { useClient } from "sanity";
671
+
592
672
  // src/lib/helpers.ts
593
673
  function parseHookUrl(url) {
674
+ if (!url) return { projectId: "", hookId: "" };
594
675
  try {
595
676
  const path = new URL(url).pathname;
596
677
  const parts = path.split("/").filter(Boolean);
@@ -680,30 +761,33 @@ function projectHref(inspectorUrl) {
680
761
  }
681
762
 
682
763
  // src/components/StatusBadge.tsx
683
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
764
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
684
765
  function StatusBadge({ state, showSpinner }) {
685
766
  const { label, tone } = stateLabel(state);
686
767
  const spinning = showSpinner && (state === "QUEUED" || state === "INITIALIZING" || state === "BUILDING");
687
768
  return /* @__PURE__ */ jsxs4(Flex, { align: "center", gap: 2, children: [
688
- spinning && /* @__PURE__ */ jsx7(Spinner, { muted: true }),
689
- /* @__PURE__ */ jsx7(Badge, { tone, padding: 2, children: label })
769
+ spinning && /* @__PURE__ */ jsx8(Spinner, { muted: true }),
770
+ /* @__PURE__ */ jsx8(Badge, { tone, padding: 2, children: label })
690
771
  ] });
691
772
  }
692
773
 
693
774
  // src/components/DeployHistory.tsx
694
775
  import { useId as useId3, useEffect as useEffect3, useState as useState4, useCallback as useCallback3 } from "react";
695
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
776
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
696
777
  function DeployHistory({ target, token, onClose }) {
697
778
  const dialogId = useId3();
779
+ const pluginConfig = usePluginConfig();
698
780
  const [deployments, setDeployments] = useState4([]);
699
781
  const [loading, setLoading] = useState4(true);
700
782
  const [error, setError] = useState4(null);
701
783
  const { projectId, hookId } = parseHookUrl(target.url);
784
+ const transport = pluginConfig.mode === "proxy" ? { mode: "proxy", proxyUrl: pluginConfig.proxyUrl ?? "", statusKey: pluginConfig.statusKey } : { mode: "direct", token };
785
+ const targetRef = { projectId, hookId, proxyKey: target.proxyKey, teamId: target.teamId };
702
786
  const load = useCallback3(async () => {
703
787
  setLoading(true);
704
788
  setError(null);
705
789
  try {
706
- const data = await listDeployments({ projectId, hookId, token, teamId: target.teamId, limit: 10 });
790
+ const data = await fetchDeployments(transport, targetRef, 20);
707
791
  setDeployments(data);
708
792
  } catch (err) {
709
793
  setError(err instanceof Error ? err.message : "Failed to load history");
@@ -714,52 +798,52 @@ function DeployHistory({ target, token, onClose }) {
714
798
  useEffect3(() => {
715
799
  load();
716
800
  }, [load]);
717
- return /* @__PURE__ */ jsx8(
801
+ return /* @__PURE__ */ jsx9(
718
802
  Dialog,
719
803
  {
720
804
  header: `${target.name} \u2014 Deployment History`,
721
805
  id: dialogId,
722
806
  onClose,
723
807
  width: 2,
724
- footer: /* @__PURE__ */ jsx8(Box, { padding: 3, children: /* @__PURE__ */ jsx8(Button, { text: "Close", icon: CloseIcon, mode: "ghost", onClick: onClose }) }),
808
+ footer: /* @__PURE__ */ jsx9(Box, { padding: 3, children: /* @__PURE__ */ jsx9(Button, { text: "Close", icon: CloseIcon, mode: "ghost", onClick: onClose }) }),
725
809
  children: /* @__PURE__ */ jsxs5(Box, { padding: 4, children: [
726
- loading && /* @__PURE__ */ jsx8(Flex, { justify: "center", padding: 6, children: /* @__PURE__ */ jsx8(Spinner, { muted: true }) }),
727
- error && /* @__PURE__ */ jsx8(Card, { tone: "critical", padding: 4, radius: 2, children: /* @__PURE__ */ jsx8(Text, { size: 1, children: error }) }),
728
- !loading && !error && deployments.length === 0 && /* @__PURE__ */ jsx8(Card, { tone: "transparent", padding: 4, children: /* @__PURE__ */ jsx8(Text, { size: 1, muted: true, align: "center", children: "No deployments found for this hook." }) }),
810
+ loading && /* @__PURE__ */ jsx9(Flex, { justify: "center", padding: 6, children: /* @__PURE__ */ jsx9(Spinner, { muted: true }) }),
811
+ error && /* @__PURE__ */ jsx9(Card, { tone: "critical", padding: 4, radius: 2, children: /* @__PURE__ */ jsx9(Text, { size: 1, children: error }) }),
812
+ !loading && !error && deployments.length === 0 && /* @__PURE__ */ jsx9(Card, { tone: "transparent", padding: 4, children: /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, align: "center", children: "No deployments found for this hook." }) }),
729
813
  !loading && deployments.length > 0 && /* @__PURE__ */ jsxs5(Stack, { space: 2, children: [
730
- /* @__PURE__ */ jsx8(Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ jsxs5(Flex, { gap: 3, children: [
731
- /* @__PURE__ */ jsx8(Box, { flex: 2, children: /* @__PURE__ */ jsx8(Text, { size: 0, weight: "semibold", muted: true, children: "Preview URL" }) }),
732
- /* @__PURE__ */ jsx8(Box, { flex: 1, children: /* @__PURE__ */ jsx8(Text, { size: 0, weight: "semibold", muted: true, children: "Status" }) }),
733
- /* @__PURE__ */ jsx8(Box, { flex: 2, children: /* @__PURE__ */ jsx8(Text, { size: 0, weight: "semibold", muted: true, children: "Branch \xB7 Commit" }) }),
734
- /* @__PURE__ */ jsx8(Box, { flex: 1, children: /* @__PURE__ */ jsx8(Text, { size: 0, weight: "semibold", muted: true, children: "Deployed" }) }),
735
- /* @__PURE__ */ jsx8(Box, { style: { width: 64 }, children: /* @__PURE__ */ jsx8(Text, { size: 0, weight: "semibold", muted: true, children: "Logs" }) })
814
+ /* @__PURE__ */ jsx9(Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ jsxs5(Flex, { gap: 3, children: [
815
+ /* @__PURE__ */ jsx9(Box, { flex: 2, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Preview URL" }) }),
816
+ /* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Status" }) }),
817
+ /* @__PURE__ */ jsx9(Box, { flex: 2, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Branch \xB7 Commit" }) }),
818
+ /* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Deployed" }) }),
819
+ /* @__PURE__ */ jsx9(Box, { style: { width: 64 }, children: /* @__PURE__ */ jsx9(Text, { size: 0, weight: "semibold", muted: true, children: "Logs" }) })
736
820
  ] }) }),
737
821
  deployments.map((d) => {
738
822
  const { label, tone } = stateLabel(d.state);
739
823
  const branch = d.meta?.githubCommitRef ?? "\u2014";
740
824
  const sha = shortSha(d.meta?.githubCommitSha);
741
825
  const message = d.meta?.githubCommitMessage?.split("\n")[0] ?? "";
742
- return /* @__PURE__ */ jsx8(Card, { padding: 3, radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs5(Flex, { gap: 3, align: "center", children: [
743
- /* @__PURE__ */ jsx8(Box, { flex: 2, style: { overflow: "hidden" }, children: deploymentHref(d.url) ? /* @__PURE__ */ jsx8(
826
+ return /* @__PURE__ */ jsx9(Card, { padding: 3, radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs5(Flex, { gap: 3, align: "center", children: [
827
+ /* @__PURE__ */ jsx9(Box, { flex: 2, style: { overflow: "hidden" }, children: deploymentHref(d.url) ? /* @__PURE__ */ jsx9(
744
828
  "a",
745
829
  {
746
830
  href: deploymentHref(d.url),
747
831
  target: "_blank",
748
832
  rel: "noreferrer",
749
833
  style: { color: "inherit" },
750
- children: /* @__PURE__ */ jsx8(Text, { size: 1, style: { textDecoration: "underline" }, children: d.url.length > 36 ? `${d.url.slice(0, 36)}\u2026` : d.url })
834
+ children: /* @__PURE__ */ jsx9(Text, { size: 1, style: { textDecoration: "underline" }, children: d.url.length > 36 ? `${d.url.slice(0, 36)}\u2026` : d.url })
751
835
  }
752
- ) : /* @__PURE__ */ jsx8(Text, { size: 1, muted: true, children: "\u2014" }) }),
753
- /* @__PURE__ */ jsx8(Box, { flex: 1, children: /* @__PURE__ */ jsx8(Badge, { tone, children: label }) }),
754
- /* @__PURE__ */ jsx8(Box, { flex: 2, style: { overflow: "hidden" }, children: /* @__PURE__ */ jsxs5(Stack, { space: 1, children: [
755
- /* @__PURE__ */ jsx8(Text, { size: 1, children: branch }),
836
+ ) : /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: "\u2014" }) }),
837
+ /* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Badge, { tone, children: label }) }),
838
+ /* @__PURE__ */ jsx9(Box, { flex: 2, style: { overflow: "hidden" }, children: /* @__PURE__ */ jsxs5(Stack, { space: 1, children: [
839
+ /* @__PURE__ */ jsx9(Text, { size: 1, children: branch }),
756
840
  sha && /* @__PURE__ */ jsxs5(Text, { size: 0, muted: true, children: [
757
841
  sha,
758
842
  message ? ` \xB7 ${message.slice(0, 40)}${message.length > 40 ? "\u2026" : ""}` : ""
759
843
  ] })
760
844
  ] }) }),
761
- /* @__PURE__ */ jsx8(Box, { flex: 1, children: /* @__PURE__ */ jsx8(Text, { size: 1, muted: true, children: timeAgo(d.created) }) }),
762
- /* @__PURE__ */ jsx8(Box, { style: { width: 64 }, children: safeHref(d.inspectorUrl) ? /* @__PURE__ */ jsx8(
845
+ /* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: timeAgo(d.created) }) }),
846
+ /* @__PURE__ */ jsx9(Box, { style: { width: 64 }, children: safeHref(d.inspectorUrl) ? /* @__PURE__ */ jsx9(
763
847
  Button,
764
848
  {
765
849
  as: "a",
@@ -772,7 +856,7 @@ function DeployHistory({ target, token, onClose }) {
772
856
  icon: LaunchIcon,
773
857
  style: { fontSize: "12px" }
774
858
  }
775
- ) : /* @__PURE__ */ jsx8(Text, { size: 1, muted: true, children: "\u2014" }) })
859
+ ) : /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: "\u2014" }) })
776
860
  ] }) }, d.uid);
777
861
  })
778
862
  ] })
@@ -782,13 +866,17 @@ function DeployHistory({ target, token, onClose }) {
782
866
  }
783
867
 
784
868
  // src/components/DeployItem.tsx
785
- import { Fragment, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
869
+ import { Fragment, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
786
870
  var POLL_INTERVAL_MS = 5e3;
787
871
  var LABEL_WIDTH = 64;
788
872
  var PENDING_TIMEOUT_MS = 6e4;
789
873
  function DeployItem({ target, token, onDelete, onEdit }) {
790
874
  const { projectId, hookId } = parseHookUrl(target.url);
791
875
  const toast = useToast();
876
+ const pluginConfig = usePluginConfig();
877
+ const client = useClient({ apiVersion: "2025-01-01" });
878
+ const transport = pluginConfig.mode === "proxy" ? { mode: "proxy", proxyUrl: pluginConfig.proxyUrl ?? "", statusKey: pluginConfig.statusKey } : { mode: "direct", token };
879
+ const targetRef = { projectId, hookId, proxyKey: target.proxyKey, teamId: target.teamId };
792
880
  const [deployments, setDeployments] = useState5([]);
793
881
  const [loadingInitial, setLoadingInitial] = useState5(true);
794
882
  const [pendingSince, setPendingSince] = useState5(null);
@@ -815,11 +903,12 @@ function DeployItem({ target, token, onDelete, onEdit }) {
815
903
  const latest = deployments[0];
816
904
  const isPending = pendingSince !== null;
817
905
  const isActive = isPending || isActiveState(latest?.state);
818
- const fetchDeployments = useCallback4(async () => {
819
- if (!projectId || !hookId || !token) return;
906
+ const fetchDeployments2 = useCallback4(async () => {
907
+ const ready = transport.mode === "proxy" ? Boolean(target.proxyKey && pluginConfig.proxyUrl) : Boolean(projectId && hookId && token);
908
+ if (!ready) return;
820
909
  const seq = ++requestSeqRef.current;
821
910
  try {
822
- const data = await listDeployments({ projectId, hookId, token, teamId: target.teamId });
911
+ const data = await fetchDeployments(transport, targetRef);
823
912
  if (seq !== requestSeqRef.current || !mountedRef.current) return;
824
913
  setDeployments(data);
825
914
  setPollError(null);
@@ -828,15 +917,15 @@ function DeployItem({ target, token, onDelete, onEdit }) {
828
917
  setPollError(err instanceof Error ? err.message : "Could not reach the Vercel API");
829
918
  console.error("Deploy-vercel-from-sanity: fetch error", err);
830
919
  }
831
- }, [projectId, hookId, token, target.teamId]);
920
+ }, [projectId, hookId, token, target.teamId, target.proxyKey, transport.mode, pluginConfig.proxyUrl]);
832
921
  useEffect4(() => {
833
- fetchDeployments().finally(() => setLoadingInitial(false));
834
- }, [fetchDeployments]);
922
+ fetchDeployments2().finally(() => setLoadingInitial(false));
923
+ }, [fetchDeployments2]);
835
924
  useEffect4(() => {
836
925
  if (!isActive) return;
837
- const id = setInterval(fetchDeployments, POLL_INTERVAL_MS);
926
+ const id = setInterval(fetchDeployments2, POLL_INTERVAL_MS);
838
927
  return () => clearInterval(id);
839
- }, [isActive, fetchDeployments]);
928
+ }, [isActive, fetchDeployments2]);
840
929
  useEffect4(() => {
841
930
  if (!isPending) return;
842
931
  if (latest?.uid && latest.uid !== triggeredFromUidRef.current) setPendingSince(null);
@@ -890,26 +979,36 @@ function DeployItem({ target, token, onDelete, onEdit }) {
890
979
  });
891
980
  void (async () => {
892
981
  try {
893
- await triggerDeploy(target.url);
894
- setTimeout(fetchDeployments, 2e3);
982
+ if (pluginConfig.mode === "proxy") {
983
+ if (!target.proxyKey) throw new Error("Target has no proxy key \u2014 set one on the deploy target");
984
+ await client.create({
985
+ _type: "vercelDeploy.request",
986
+ target: { _type: "reference", _ref: target._id },
987
+ proxyKey: target.proxyKey,
988
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString()
989
+ });
990
+ } else {
991
+ await triggerDeploy(target.url ?? "");
992
+ }
993
+ setTimeout(fetchDeployments2, 2e3);
895
994
  } catch (err) {
896
995
  setPendingSince(null);
897
996
  setDeployError(err instanceof Error ? err.message : "Deploy failed");
898
997
  }
899
998
  })();
900
- }, [target.url, fetchDeployments, latest?.uid]);
999
+ }, [target.url, target.proxyKey, target._id, pluginConfig.mode, client, fetchDeployments2, latest?.uid]);
901
1000
  const cancel = useCallback4(async () => {
902
1001
  if (!latest?.uid) return;
903
1002
  setCanceling(true);
904
1003
  try {
905
- await cancelDeployment({ deploymentId: latest.uid, token, teamId: target.teamId });
906
- await fetchDeployments();
1004
+ await cancelDeploy(transport, targetRef, latest.uid);
1005
+ await fetchDeployments2();
907
1006
  } catch (err) {
908
1007
  console.error("deploy-vercel-from-sanity: cancel error", err);
909
1008
  } finally {
910
1009
  setCanceling(false);
911
1010
  }
912
- }, [latest?.uid, token, target.teamId, fetchDeployments]);
1011
+ }, [latest?.uid, token, target.teamId, fetchDeployments2]);
913
1012
  const copyUrl = useCallback4(() => {
914
1013
  if (!latest?.url) return;
915
1014
  const fullUrl = deploymentHref(latest.url) ?? "";
@@ -925,11 +1024,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
925
1024
  setLoadingLogs(true);
926
1025
  setLogError(null);
927
1026
  try {
928
- const events = await getDeploymentEvents({
929
- deploymentId: latest.uid,
930
- token,
931
- teamId: target.teamId
932
- });
1027
+ const events = await fetchDeploymentEvents(transport, targetRef, latest.uid);
933
1028
  const lines = events.filter((e) => e.type === "stderr" || e.type === "stdout").map((e) => e.text ?? "").filter(Boolean).reverse().slice(-30);
934
1029
  setErrorLines(lines.length > 0 ? lines : ["No stderr or stdout was captured for this build. Open the full build log in Vercel for details."]);
935
1030
  } catch (err) {
@@ -952,19 +1047,19 @@ function DeployItem({ target, token, onDelete, onEdit }) {
952
1047
  const vercelProjectUrl = projectHref(latest?.inspectorUrl);
953
1048
  const isError = latest?.state === "ERROR";
954
1049
  return /* @__PURE__ */ jsxs6(Fragment, { children: [
955
- /* @__PURE__ */ jsx9(Card, { radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs6(Flex, { align: "stretch", className: "dvfs-card-flex", children: [
1050
+ /* @__PURE__ */ jsx10(Card, { radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs6(Flex, { align: "stretch", className: "dvfs-card-flex", children: [
956
1051
  /* @__PURE__ */ jsxs6(Flex, { direction: "column", flex: 1, style: { minWidth: 0 }, children: [
957
1052
  /* @__PURE__ */ jsxs6(Stack, { space: 3, padding: 3, style: { flex: 1 }, children: [
958
1053
  /* @__PURE__ */ jsxs6(Flex, { align: "center", justify: "space-between", gap: 2, children: [
959
1054
  /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, style: { minWidth: 0, flexWrap: "wrap" }, children: [
960
- /* @__PURE__ */ jsx9(Text, { size: 2, weight: "semibold", style: { flexShrink: 0 }, children: target.name }),
961
- branch && /* @__PURE__ */ jsx9(Badge, { tone: "default", padding: 2, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
1055
+ /* @__PURE__ */ jsx10(Text, { size: 2, weight: "semibold", style: { flexShrink: 0 }, children: target.name }),
1056
+ branch && /* @__PURE__ */ jsx10(Badge, { tone: "default", padding: 2, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
962
1057
  branch,
963
- /* @__PURE__ */ jsx9("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", style: { marginLeft: "-0.1em", opacity: 0.5 }, children: /* @__PURE__ */ jsx9("path", { d: "M5 3.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm0 2.122a2.25 2.25 0 1 0-1.5 0v.878A2.25 2.25 0 0 0 5.75 8.5h1.5v2.128a2.251 2.251 0 1 0 1.5 0V8.5h1.5a2.25 2.25 0 0 0 2.25-2.25v-.878a2.25 2.25 0 1 0-1.5 0v.878a.75.75 0 0 1-.75.75h-4.5A.75.75 0 0 1 5 6.25v-.878zm3.75 7.378a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm3-8.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0z" }) })
1058
+ /* @__PURE__ */ jsx10("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", style: { marginLeft: "-0.1em", opacity: 0.5 }, children: /* @__PURE__ */ jsx10("path", { d: "M5 3.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm0 2.122a2.25 2.25 0 1 0-1.5 0v.878A2.25 2.25 0 0 0 5.75 8.5h1.5v2.128a2.251 2.251 0 1 0 1.5 0V8.5h1.5a2.25 2.25 0 0 0 2.25-2.25v-.878a2.25 2.25 0 1 0-1.5 0v.878a.75.75 0 0 1-.75.75h-4.5A.75.75 0 0 1 5 6.25v-.878zm3.75 7.378a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0zm3-8.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0z" }) })
964
1059
  ] }) }),
965
1060
  token && !loadingInitial && /* @__PURE__ */ jsxs6(Fragment, { children: [
966
- isPending ? /* @__PURE__ */ jsx9(StatusBadge, { state: "QUEUED" }) : /* @__PURE__ */ jsx9(StatusBadge, { state: latest?.state }),
967
- isActiveState(latest?.state) && /* @__PURE__ */ jsx9(
1061
+ isPending ? /* @__PURE__ */ jsx10(StatusBadge, { state: "QUEUED" }) : /* @__PURE__ */ jsx10(StatusBadge, { state: latest?.state }),
1062
+ isActiveState(latest?.state) && /* @__PURE__ */ jsx10(
968
1063
  Button,
969
1064
  {
970
1065
  text: "Cancel",
@@ -978,14 +1073,14 @@ function DeployItem({ target, token, onDelete, onEdit }) {
978
1073
  ),
979
1074
  isPending ? (
980
1075
  /* Optimistic — dimmed spinner only; no elapsed time until a real build exists */
981
- /* @__PURE__ */ jsx9(Spinner, { muted: true, style: { marginLeft: 4, opacity: 0.5 } })
1076
+ /* @__PURE__ */ jsx10(Spinner, { muted: true, style: { marginLeft: 4, opacity: 0.5 } })
982
1077
  ) : isActive ? /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
983
- /* @__PURE__ */ jsx9(Spinner, { muted: true, style: { marginLeft: 4 } }),
984
- /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: formatDuration(elapsed) })
985
- ] }) : deployedAt ? /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: deployedAt }) : null
1078
+ /* @__PURE__ */ jsx10(Spinner, { muted: true, style: { marginLeft: 4 } }),
1079
+ /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: formatDuration(elapsed) })
1080
+ ] }) : deployedAt ? /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: deployedAt }) : null
986
1081
  ] })
987
1082
  ] }),
988
- /* @__PURE__ */ jsx9(
1083
+ /* @__PURE__ */ jsx10(
989
1084
  ActionMenu,
990
1085
  {
991
1086
  id: `menu-${target._id}`,
@@ -1001,32 +1096,32 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1001
1096
  }
1002
1097
  )
1003
1098
  ] }),
1004
- /* @__PURE__ */ jsx9("hr", { style: { border: "none", borderTop: "1px solid currentColor", opacity: 0.1, margin: 0 } }),
1005
- !token ? /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: "Connect a Vercel API token to see deployment status." }) : loadingInitial ? /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
1006
- /* @__PURE__ */ jsx9(Spinner, { muted: true }),
1007
- /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: "Loading\u2026" })
1099
+ /* @__PURE__ */ jsx10("hr", { style: { border: "none", borderTop: "1px solid currentColor", opacity: 0.1, margin: 0 } }),
1100
+ !token ? /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: pluginConfig.mode === "proxy" ? target.proxyKey ? "Waiting for status from the deploy proxy." : "Set a Proxy Key on this target to see deployment status." : "Connect a Vercel API token to see deployment status." }) : loadingInitial ? /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
1101
+ /* @__PURE__ */ jsx10(Spinner, { muted: true }),
1102
+ /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: "Loading\u2026" })
1008
1103
  ] }) : /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
1009
1104
  /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, wrap: "wrap", children: [
1010
- latest?.url && latest.state === "READY" && /* @__PURE__ */ jsx9(Fragment, { children: /* @__PURE__ */ jsx9(
1105
+ latest?.url && latest.state === "READY" && /* @__PURE__ */ jsx10(Fragment, { children: /* @__PURE__ */ jsx10(
1011
1106
  "a",
1012
1107
  {
1013
1108
  href: deploymentHref(latest.url),
1014
1109
  target: "_blank",
1015
1110
  rel: "noreferrer",
1016
1111
  style: { color: "inherit" },
1017
- children: /* @__PURE__ */ jsx9(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsx9(Text, { size: 1, children: latest.url }) })
1112
+ children: /* @__PURE__ */ jsx10(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ jsx10(Text, { size: 1, children: latest.url }) })
1018
1113
  }
1019
1114
  ) }),
1020
- sha && /* @__PURE__ */ jsx9(Tooltip, { text: commitMsg ?? sha, children: commitHref ? /* @__PURE__ */ jsx9(
1115
+ sha && /* @__PURE__ */ jsx10(Tooltip, { text: commitMsg ?? sha, children: commitHref ? /* @__PURE__ */ jsx10(
1021
1116
  "a",
1022
1117
  {
1023
1118
  href: commitHref,
1024
1119
  target: "_blank",
1025
1120
  rel: "noreferrer",
1026
1121
  style: { color: "inherit", textDecoration: "none" },
1027
- children: /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, style: { cursor: "pointer", fontFamily: "monospace" }, children: sha })
1122
+ children: /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, style: { cursor: "pointer", fontFamily: "monospace" }, children: sha })
1028
1123
  }
1029
- ) : /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, style: { cursor: "default", fontFamily: "monospace" }, children: sha }) }),
1124
+ ) : /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, style: { cursor: "default", fontFamily: "monospace" }, children: sha }) }),
1030
1125
  creator && /* @__PURE__ */ jsxs6(Text, { size: 1, muted: true, children: [
1031
1126
  "by ",
1032
1127
  creator
@@ -1037,7 +1132,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1037
1132
  " to build"
1038
1133
  ] }),
1039
1134
  latest?.url && latest.state === "READY" && /* @__PURE__ */ jsxs6(Fragment, { children: [
1040
- /* @__PURE__ */ jsx9(Tooltip, { text: copied ? "Copied" : "Copy deployment URL", children: /* @__PURE__ */ jsx9(
1135
+ /* @__PURE__ */ jsx10(Tooltip, { text: copied ? "Copied" : "Copy deployment URL", children: /* @__PURE__ */ jsx10(
1041
1136
  Button,
1042
1137
  {
1043
1138
  mode: "ghost",
@@ -1049,7 +1144,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1049
1144
  style: { cursor: "pointer" }
1050
1145
  }
1051
1146
  ) }),
1052
- /* @__PURE__ */ jsx9(
1147
+ /* @__PURE__ */ jsx10(
1053
1148
  "span",
1054
1149
  {
1055
1150
  role: "status",
@@ -1068,7 +1163,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1068
1163
  ] })
1069
1164
  ] }),
1070
1165
  /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, wrap: "wrap", children: [
1071
- commitMsg && /* @__PURE__ */ jsx9(
1166
+ commitMsg && /* @__PURE__ */ jsx10(
1072
1167
  Text,
1073
1168
  {
1074
1169
  size: 0,
@@ -1078,7 +1173,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1078
1173
  }
1079
1174
  ),
1080
1175
  isError && /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
1081
- /* @__PURE__ */ jsx9(
1176
+ /* @__PURE__ */ jsx10(
1082
1177
  Button,
1083
1178
  {
1084
1179
  "aria-expanded": showErrorLogs,
@@ -1094,30 +1189,30 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1094
1189
  ),
1095
1190
  showErrorLogs && /* @__PURE__ */ jsxs6(Card, { tone: "critical", radius: 2, padding: 3, children: [
1096
1191
  loadingLogs && /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
1097
- /* @__PURE__ */ jsx9(Spinner, { muted: true }),
1098
- /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: "Loading logs\u2026" })
1192
+ /* @__PURE__ */ jsx10(Spinner, { muted: true }),
1193
+ /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: "Loading logs\u2026" })
1099
1194
  ] }),
1100
1195
  logError && /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
1101
- /* @__PURE__ */ jsx9(Text, { size: 1, children: logError }),
1102
- safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx9("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
1103
- /* @__PURE__ */ jsx9(LaunchIcon, {}),
1104
- /* @__PURE__ */ jsx9(Text, { size: 1, children: "View full logs in Vercel" })
1196
+ /* @__PURE__ */ jsx10(Text, { size: 1, children: logError }),
1197
+ safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx10("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
1198
+ /* @__PURE__ */ jsx10(LaunchIcon, {}),
1199
+ /* @__PURE__ */ jsx10(Text, { size: 1, children: "View full logs in Vercel" })
1105
1200
  ] }) })
1106
1201
  ] }),
1107
1202
  !loadingLogs && !logError && errorLines.length > 0 && /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
1108
- /* @__PURE__ */ jsx9(Box, { style: { maxHeight: 240, overflowY: "auto", fontFamily: "monospace", fontSize: 13, lineHeight: 1.6 }, children: errorLines.map((line, i) => /* @__PURE__ */ jsx9(Code, { style: { display: "block", whiteSpace: "pre-wrap", wordBreak: "break-all" }, children: line }, i)) }),
1109
- safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx9("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
1110
- /* @__PURE__ */ jsx9(LaunchIcon, {}),
1111
- /* @__PURE__ */ jsx9(Text, { size: 1, children: "View full logs in Vercel" })
1203
+ /* @__PURE__ */ jsx10(Box, { style: { maxHeight: 240, overflowY: "auto", fontFamily: "monospace", fontSize: 13, lineHeight: 1.6 }, children: errorLines.map((line, i) => /* @__PURE__ */ jsx10(Code, { style: { display: "block", whiteSpace: "pre-wrap", wordBreak: "break-all" }, children: line }, i)) }),
1204
+ safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsx10("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
1205
+ /* @__PURE__ */ jsx10(LaunchIcon, {}),
1206
+ /* @__PURE__ */ jsx10(Text, { size: 1, children: "View full logs in Vercel" })
1112
1207
  ] }) })
1113
1208
  ] })
1114
1209
  ] })
1115
1210
  ] }),
1116
- deployError && /* @__PURE__ */ jsx9(Card, { tone: "critical", padding: 2, radius: 2, children: /* @__PURE__ */ jsx9(Text, { size: 1, children: deployError }) })
1211
+ deployError && /* @__PURE__ */ jsx10(Card, { tone: "critical", padding: 2, radius: 2, children: /* @__PURE__ */ jsx10(Text, { size: 1, children: deployError }) })
1117
1212
  ] })
1118
1213
  ] }),
1119
- pollError && /* @__PURE__ */ jsx9(Card, { tone: "caution", padding: 3, radius: 2, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
1120
- /* @__PURE__ */ jsx9(WarningOutlineIcon, { "aria-hidden": "true" }),
1214
+ pollError && /* @__PURE__ */ jsx10(Card, { tone: "caution", padding: 3, radius: 2, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
1215
+ /* @__PURE__ */ jsx10(WarningOutlineIcon, { "aria-hidden": "true" }),
1121
1216
  /* @__PURE__ */ jsxs6(Text, { size: 1, children: [
1122
1217
  "Status updates paused \u2014 ",
1123
1218
  pollError
@@ -1125,7 +1220,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1125
1220
  ] }) })
1126
1221
  ] }),
1127
1222
  /* @__PURE__ */ jsxs6(Box, { children: [
1128
- /* @__PURE__ */ jsx9(
1223
+ /* @__PURE__ */ jsx10(
1129
1224
  Button,
1130
1225
  {
1131
1226
  mode: "ghost",
@@ -1138,61 +1233,61 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1138
1233
  style: { width: "100%", justifyContent: "flex-start", borderRadius: 0, cursor: "pointer" }
1139
1234
  }
1140
1235
  ),
1141
- showDetails && /* @__PURE__ */ jsx9(Card, { tone: "primary", padding: 3, className: "dvfs-accordion-content", style: { borderRadius: 0, borderTop: "1px solid rgba(128,128,128,0.15)" }, children: /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
1236
+ showDetails && /* @__PURE__ */ jsx10(Card, { tone: "primary", padding: 3, className: "dvfs-accordion-content", style: { borderRadius: 0, borderTop: "1px solid rgba(128,128,128,0.15)" }, children: /* @__PURE__ */ jsxs6(Stack, { space: 2, children: [
1142
1237
  /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
1143
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Project" }),
1144
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: projectId || "\u2014" })
1238
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Project" }),
1239
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: projectId || "\u2014" })
1145
1240
  ] }),
1146
1241
  /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
1147
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Hook" }),
1148
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: hookId || "\u2014" })
1242
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Hook" }),
1243
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: hookId || "\u2014" })
1149
1244
  ] }),
1150
1245
  target.teamId && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
1151
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Team" }),
1152
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: target.teamId })
1246
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Team" }),
1247
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: target.teamId })
1153
1248
  ] }),
1154
1249
  fullSha && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "flex-start", children: [
1155
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Commit" }),
1156
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: fullSha })
1250
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Commit" }),
1251
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: fullSha })
1157
1252
  ] }),
1158
1253
  latest?.meta?.githubCommitAuthorName && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
1159
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Author" }),
1160
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, children: latest.meta.githubCommitAuthorName })
1254
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Author" }),
1255
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, children: latest.meta.githubCommitAuthorName })
1161
1256
  ] }),
1162
1257
  branch && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
1163
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Branch" }),
1164
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: branch })
1258
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Branch" }),
1259
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: branch })
1165
1260
  ] }),
1166
1261
  latest?.uid && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
1167
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Deploy ID" }),
1168
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: latest.uid })
1262
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Deploy ID" }),
1263
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: latest.uid })
1169
1264
  ] }),
1170
1265
  latest?.url && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "flex-start", children: [
1171
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "URL" }),
1172
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: latest.url })
1266
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "URL" }),
1267
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: latest.url })
1173
1268
  ] }),
1174
1269
  safeHref(latest?.inspectorUrl) && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
1175
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Inspector" }),
1176
- /* @__PURE__ */ jsx9("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
1177
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: "Open in Vercel" }),
1178
- /* @__PURE__ */ jsx9(LaunchIcon, { style: { width: 10, height: 10 } })
1270
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Inspector" }),
1271
+ /* @__PURE__ */ jsx10("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 1, children: [
1272
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: "Open in Vercel" }),
1273
+ /* @__PURE__ */ jsx10(LaunchIcon, { style: { width: 10, height: 10 } })
1179
1274
  ] }) })
1180
1275
  ] }),
1181
1276
  latest?.created && /* @__PURE__ */ jsxs6(Flex, { gap: 2, align: "center", children: [
1182
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Created" }),
1183
- /* @__PURE__ */ jsx9(Text, { size: 0, muted: true, children: new Date(latest.created).toLocaleString() })
1277
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Created" }),
1278
+ /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, children: new Date(latest.created).toLocaleString() })
1184
1279
  ] })
1185
1280
  ] }) })
1186
1281
  ] })
1187
1282
  ] }),
1188
- /* @__PURE__ */ jsx9(
1283
+ /* @__PURE__ */ jsx10(
1189
1284
  Flex,
1190
1285
  {
1191
1286
  direction: "column",
1192
1287
  gap: 2,
1193
1288
  className: "dvfs-deploy-col",
1194
1289
  style: { flexShrink: 0, alignSelf: "stretch" },
1195
- children: /* @__PURE__ */ jsx9(
1290
+ children: /* @__PURE__ */ jsx10(
1196
1291
  Button,
1197
1292
  {
1198
1293
  text: "Deploy",
@@ -1212,7 +1307,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1212
1307
  }
1213
1308
  )
1214
1309
  ] }) }),
1215
- showHistory && /* @__PURE__ */ jsx9(
1310
+ showHistory && /* @__PURE__ */ jsx10(
1216
1311
  DeployHistory,
1217
1312
  {
1218
1313
  target,
@@ -1225,13 +1320,13 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1225
1320
 
1226
1321
  // src/components/TokenSetup.tsx
1227
1322
  import { useId as useId4, useState as useState6, useCallback as useCallback5 } from "react";
1228
- import { useClient } from "sanity";
1229
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1323
+ import { useClient as useClient2 } from "sanity";
1324
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
1230
1325
  var TOKEN_DOC_ID = "config.vercelDeploy";
1231
1326
  function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1232
1327
  const dialogId = useId4();
1233
1328
  const tokenId = useId4();
1234
- const client = useClient({ apiVersion: "2025-01-01" });
1329
+ const client = useClient2({ apiVersion: "2025-01-01" });
1235
1330
  const [token, setToken] = useState6("");
1236
1331
  const [saving, setSaving] = useState6(false);
1237
1332
  const [error, setError] = useState6(null);
@@ -1265,7 +1360,7 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1265
1360
  setRevoking(false);
1266
1361
  }
1267
1362
  }, [client, onSaved]);
1268
- return /* @__PURE__ */ jsx10(
1363
+ return /* @__PURE__ */ jsx11(
1269
1364
  Dialog,
1270
1365
  {
1271
1366
  header: "Connect Vercel API token",
@@ -1273,7 +1368,7 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1273
1368
  onClose: onCancel,
1274
1369
  width: 1,
1275
1370
  footer: /* @__PURE__ */ jsxs7(Flex, { padding: 3, gap: 2, justify: hasToken ? "space-between" : "flex-end", children: [
1276
- hasToken && /* @__PURE__ */ jsx10(
1371
+ hasToken && /* @__PURE__ */ jsx11(
1277
1372
  Button,
1278
1373
  {
1279
1374
  text: "Remove token",
@@ -1287,8 +1382,8 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1287
1382
  }
1288
1383
  ),
1289
1384
  /* @__PURE__ */ jsxs7(Flex, { gap: 2, children: [
1290
- onCancel && /* @__PURE__ */ jsx10(Button, { text: "Cancel", mode: "ghost", onClick: onCancel, style: { cursor: "pointer" } }),
1291
- /* @__PURE__ */ jsx10(
1385
+ onCancel && /* @__PURE__ */ jsx11(Button, { text: "Cancel", mode: "ghost", onClick: onCancel, style: { cursor: "pointer" } }),
1386
+ /* @__PURE__ */ jsx11(
1292
1387
  Button,
1293
1388
  {
1294
1389
  text: "Save and connect",
@@ -1304,19 +1399,20 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1304
1399
  ] }),
1305
1400
  children: /* @__PURE__ */ jsxs7(Stack, { space: 4, padding: 4, children: [
1306
1401
  /* @__PURE__ */ jsxs7(Stack, { space: 3, children: [
1307
- /* @__PURE__ */ jsx10(Text, { size: 1, muted: true, children: "A Vercel API token lets this tool read deployment status, history, build logs, and branch metadata. Without it you can still trigger deploys \u2014 you just won't see any feedback." }),
1402
+ /* @__PURE__ */ jsx11(Text, { size: 1, muted: true, children: "A Vercel API token lets this tool read deployment status, history, build logs, and branch metadata. Without it you can still trigger deploys \u2014 you just won't see any feedback." }),
1308
1403
  /* @__PURE__ */ jsxs7(Text, { size: 1, muted: true, children: [
1309
1404
  "Create one at ",
1310
- /* @__PURE__ */ jsx10("strong", { children: "vercel.com \u2192 Settings \u2192 Tokens" }),
1405
+ /* @__PURE__ */ jsx11("strong", { children: "vercel.com \u2192 Settings \u2192 Tokens" }),
1311
1406
  " with",
1312
1407
  " ",
1313
- /* @__PURE__ */ jsx10("strong", { children: "Full Account" }),
1314
- " scope. The token is stored in your Sanity dataset and shared across all authenticated studio users."
1408
+ "scope limited to the ",
1409
+ /* @__PURE__ */ jsx11("strong", { children: "team" }),
1410
+ " that owns your projects. The token is stored in cleartext in your Sanity dataset \u2014 readable by anyone who can read the dataset, including unauthenticated readers if it is public and shared across all authenticated studio users."
1315
1411
  ] })
1316
1412
  ] }),
1317
1413
  /* @__PURE__ */ jsxs7(Stack, { space: 2, children: [
1318
- /* @__PURE__ */ jsx10(Label, { as: "label", size: 1, htmlFor: tokenId, children: "Vercel API Token" }),
1319
- /* @__PURE__ */ jsx10(
1414
+ /* @__PURE__ */ jsx11(Label, { as: "label", size: 1, htmlFor: tokenId, children: "Vercel API Token" }),
1415
+ /* @__PURE__ */ jsx11(
1320
1416
  TextInput,
1321
1417
  {
1322
1418
  id: tokenId,
@@ -1327,7 +1423,7 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1327
1423
  }
1328
1424
  )
1329
1425
  ] }),
1330
- error && /* @__PURE__ */ jsx10(Card, { tone: "critical", padding: 3, radius: 2, role: "alert", children: /* @__PURE__ */ jsx10(Text, { size: 1, children: error }) })
1426
+ error && /* @__PURE__ */ jsx11(Card, { tone: "critical", padding: 3, radius: 2, role: "alert", children: /* @__PURE__ */ jsx11(Text, { size: 1, children: error }) })
1331
1427
  ] })
1332
1428
  }
1333
1429
  );
@@ -1335,12 +1431,14 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1335
1431
 
1336
1432
  // src/components/DeployTargetForm.tsx
1337
1433
  import { useId as useId5, useState as useState7, useCallback as useCallback6 } from "react";
1338
- import { useClient as useClient2 } from "sanity";
1339
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1434
+ import { useClient as useClient3 } from "sanity";
1435
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
1340
1436
  var VERCEL_HOOK_RE2 = /^https:\/\/api\.vercel\.com\/v1\/integrations\/deploy\//;
1341
1437
  function DeployTargetForm({ initial, onSaved, onClose }) {
1342
- const client = useClient2({ apiVersion: "2025-01-01" });
1438
+ const client = useClient3({ apiVersion: "2025-01-01" });
1343
1439
  const isEdit = Boolean(initial);
1440
+ const pluginConfig = usePluginConfig();
1441
+ const proxyKeyId = useId5();
1344
1442
  const dialogId = useId5();
1345
1443
  const nameId = useId5();
1346
1444
  const urlId = useId5();
@@ -1352,11 +1450,13 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1352
1450
  const [name, setName] = useState7(initial?.name ?? "");
1353
1451
  const [url, setUrl] = useState7(initial?.url ?? "");
1354
1452
  const [teamId, setTeamId] = useState7(initial?.teamId ?? "");
1453
+ const [proxyKey, setProxyKey] = useState7(initial?.proxyKey ?? "");
1355
1454
  const [disableDelete, setDisableDelete] = useState7(initial?.disableDeleteAction ?? false);
1356
1455
  const [saving, setSaving] = useState7(false);
1357
1456
  const [error, setError] = useState7(null);
1358
1457
  const urlValid = !url || VERCEL_HOOK_RE2.test(url.trim());
1359
- const canSave = name.trim() && url.trim() && urlValid;
1458
+ const isProxy = pluginConfig.mode === "proxy";
1459
+ const canSave = Boolean(name.trim()) && urlValid && (isProxy ? Boolean(proxyKey.trim()) : Boolean(url.trim()));
1360
1460
  const save = useCallback6(async () => {
1361
1461
  if (!canSave) return;
1362
1462
  setSaving(true);
@@ -1365,6 +1465,7 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1365
1465
  name: name.trim(),
1366
1466
  url: url.trim(),
1367
1467
  teamId: teamId.trim() || null,
1468
+ proxyKey: proxyKey.trim() || null,
1368
1469
  disableDeleteAction: disableDelete
1369
1470
  };
1370
1471
  try {
@@ -1379,8 +1480,8 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1379
1480
  } finally {
1380
1481
  setSaving(false);
1381
1482
  }
1382
- }, [canSave, isEdit, initial, client, name, url, teamId, disableDelete, onSaved]);
1383
- return /* @__PURE__ */ jsx11(
1483
+ }, [canSave, isEdit, initial, client, name, url, teamId, proxyKey, disableDelete, onSaved]);
1484
+ return /* @__PURE__ */ jsx12(
1384
1485
  Dialog,
1385
1486
  {
1386
1487
  header: isEdit ? `Edit "${initial?.name}"` : "Add deploy target",
@@ -1388,8 +1489,8 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1388
1489
  onClose,
1389
1490
  width: 1,
1390
1491
  footer: /* @__PURE__ */ jsxs8(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
1391
- /* @__PURE__ */ jsx11(Button, { text: "Cancel", mode: "ghost", onClick: onClose, style: { cursor: "pointer" } }),
1392
- /* @__PURE__ */ jsx11(
1492
+ /* @__PURE__ */ jsx12(Button, { text: "Cancel", mode: "ghost", onClick: onClose, style: { cursor: "pointer" } }),
1493
+ /* @__PURE__ */ jsx12(
1393
1494
  Button,
1394
1495
  {
1395
1496
  text: isEdit ? "Save changes" : "Add target",
@@ -1402,13 +1503,13 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1402
1503
  }
1403
1504
  )
1404
1505
  ] }),
1405
- children: /* @__PURE__ */ jsx11(Box, { padding: 4, children: /* @__PURE__ */ jsxs8(Stack, { space: 4, children: [
1506
+ children: /* @__PURE__ */ jsx12(Box, { padding: 4, children: /* @__PURE__ */ jsxs8(Stack, { space: 4, children: [
1406
1507
  /* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
1407
1508
  /* @__PURE__ */ jsxs8(Label, { as: "label", size: 1, htmlFor: nameId, children: [
1408
1509
  "Name ",
1409
- /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: "*" })
1510
+ /* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "*" })
1410
1511
  ] }),
1411
- /* @__PURE__ */ jsx11(
1512
+ /* @__PURE__ */ jsx12(
1412
1513
  TextInput,
1413
1514
  {
1414
1515
  id: nameId,
@@ -1420,12 +1521,29 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1420
1521
  }
1421
1522
  )
1422
1523
  ] }),
1423
- /* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
1524
+ isProxy ? /* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
1525
+ /* @__PURE__ */ jsxs8(Label, { as: "label", size: 1, htmlFor: proxyKeyId, children: [
1526
+ "Proxy Key ",
1527
+ /* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "*" })
1528
+ ] }),
1529
+ /* @__PURE__ */ jsx12(
1530
+ TextInput,
1531
+ {
1532
+ id: proxyKeyId,
1533
+ required: true,
1534
+ "aria-required": "true",
1535
+ value: proxyKey,
1536
+ onChange: (e) => setProxyKey(e.target.value),
1537
+ placeholder: "production"
1538
+ }
1539
+ ),
1540
+ /* @__PURE__ */ jsx12(Text, { size: 0, muted: true, children: "Matches a key configured on your deploy proxy, which holds the real hook URL. Contains no secret." })
1541
+ ] }) : /* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
1424
1542
  /* @__PURE__ */ jsxs8(Label, { as: "label", size: 1, htmlFor: urlId, children: [
1425
1543
  "Deploy hook URL ",
1426
- /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: "*" })
1544
+ /* @__PURE__ */ jsx12("span", { "aria-hidden": "true", children: "*" })
1427
1545
  ] }),
1428
- /* @__PURE__ */ jsx11(
1546
+ /* @__PURE__ */ jsx12(
1429
1547
  TextInput,
1430
1548
  {
1431
1549
  id: urlId,
@@ -1438,15 +1556,15 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1438
1556
  placeholder: "https://api.vercel.com/v1/integrations/deploy/\u2026"
1439
1557
  }
1440
1558
  ),
1441
- url && !urlValid && /* @__PURE__ */ jsx11(Card, { tone: "critical", padding: 2, radius: 2, role: "alert", children: /* @__PURE__ */ jsx11(Text, { id: urlErrorId, size: 1, children: "Must be a Vercel deploy hook URL (api.vercel.com/v1/integrations/deploy/\u2026)" }) }),
1442
- /* @__PURE__ */ jsx11(Text, { id: urlHelpId, size: 0, muted: true, children: "Vercel dashboard \u2192 Project \u2192 Settings \u2192 Git \u2192 Deploy Hooks" })
1559
+ url && !urlValid && /* @__PURE__ */ jsx12(Card, { tone: "critical", padding: 2, radius: 2, role: "alert", children: /* @__PURE__ */ jsx12(Text, { id: urlErrorId, size: 1, children: "Must be a Vercel deploy hook URL (api.vercel.com/v1/integrations/deploy/\u2026)" }) }),
1560
+ /* @__PURE__ */ jsx12(Text, { id: urlHelpId, size: 0, muted: true, children: "Vercel dashboard \u2192 Project \u2192 Settings \u2192 Git \u2192 Deploy Hooks" })
1443
1561
  ] }),
1444
1562
  /* @__PURE__ */ jsxs8(Stack, { space: 2, children: [
1445
1563
  /* @__PURE__ */ jsxs8(Label, { as: "label", size: 1, htmlFor: teamId_, children: [
1446
1564
  "Team ID ",
1447
- /* @__PURE__ */ jsx11("span", { style: { opacity: 0.5, fontWeight: "normal" }, children: "\u2014 optional" })
1565
+ /* @__PURE__ */ jsx12("span", { style: { opacity: 0.5, fontWeight: "normal" }, children: "\u2014 optional" })
1448
1566
  ] }),
1449
- /* @__PURE__ */ jsx11(
1567
+ /* @__PURE__ */ jsx12(
1450
1568
  TextInput,
1451
1569
  {
1452
1570
  id: teamId_,
@@ -1456,14 +1574,10 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1456
1574
  placeholder: "team_xxxxxxxx"
1457
1575
  }
1458
1576
  ),
1459
- /* @__PURE__ */ jsxs8(Text, { id: teamHelpId, size: 0, muted: true, children: [
1460
- "Required for team-owned Vercel projects. Find it at Vercel \u2192 Settings \u2192 General \u2192 Team ID (starts with ",
1461
- /* @__PURE__ */ jsx11("code", { children: "team_" }),
1462
- ")."
1463
- ] })
1577
+ /* @__PURE__ */ jsx12(Text, { id: teamHelpId, size: 0, muted: true, children: isProxy ? "Not used in proxy mode \u2014 the proxy supplies the team from its own configuration." : "Required for team-owned Vercel projects. Find it at Vercel \u2192 Settings \u2192 General \u2192 Team ID (starts with team_)." })
1464
1578
  ] }),
1465
1579
  /* @__PURE__ */ jsxs8(Flex, { align: "center", gap: 3, children: [
1466
- /* @__PURE__ */ jsx11(
1580
+ /* @__PURE__ */ jsx12(
1467
1581
  Switch,
1468
1582
  {
1469
1583
  checked: disableDelete,
@@ -1472,25 +1586,27 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1472
1586
  }
1473
1587
  ),
1474
1588
  /* @__PURE__ */ jsxs8(Stack, { space: 1, children: [
1475
- /* @__PURE__ */ jsx11(Label, { as: "label", size: 1, htmlFor: disableId, children: "Disable delete action" }),
1476
- /* @__PURE__ */ jsx11(Text, { size: 0, muted: true, children: "Hides the delete button for this target in the studio." })
1589
+ /* @__PURE__ */ jsx12(Label, { as: "label", size: 1, htmlFor: disableId, children: "Disable delete action" }),
1590
+ /* @__PURE__ */ jsx12(Text, { size: 0, muted: true, children: "Hides the delete button for this target in the studio." })
1477
1591
  ] })
1478
1592
  ] }),
1479
- error && /* @__PURE__ */ jsx11(Card, { tone: "critical", padding: 3, radius: 2, children: /* @__PURE__ */ jsx11(Text, { size: 1, children: error }) })
1593
+ error && /* @__PURE__ */ jsx12(Card, { tone: "critical", padding: 3, radius: 2, children: /* @__PURE__ */ jsx12(Text, { size: 1, children: error }) })
1480
1594
  ] }) })
1481
1595
  }
1482
1596
  );
1483
1597
  }
1484
1598
 
1485
1599
  // src/version.ts
1486
- var VERSION = "1.2.1";
1600
+ var VERSION = "1.3.1";
1487
1601
 
1488
1602
  // src/components/DeployTool.tsx
1489
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1603
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
1490
1604
  var TOKEN_QUERY = `*[_id == "config.vercelDeploy"][0].accessToken`;
1491
1605
  var TARGETS_QUERY = `*[_type == "vercel_deploy" && !(_id in path("drafts.**"))] | order(_createdAt asc)`;
1492
1606
  function DeployTool() {
1493
- const client = useClient3({ apiVersion: "2025-01-01" });
1607
+ const client = useClient4({ apiVersion: "2025-01-01" });
1608
+ const pluginConfig = usePluginConfig();
1609
+ const usesToken = pluginConfig.mode === "direct";
1494
1610
  const toast = useToast();
1495
1611
  const [token, setToken] = useState8(null);
1496
1612
  const [targets, setTargets] = useState8([]);
@@ -1581,14 +1697,14 @@ function DeployTool() {
1581
1697
  }
1582
1698
  }, [client, pendingDelete, toast]);
1583
1699
  if (loading) {
1584
- return /* @__PURE__ */ jsx12(Card, { height: "fill", tone: "transparent", children: /* @__PURE__ */ jsx12(Flex, { align: "center", justify: "center", height: "fill", children: /* @__PURE__ */ jsx12(Spinner, { muted: true }) }) });
1700
+ return /* @__PURE__ */ jsx13(Card, { height: "fill", tone: "transparent", children: /* @__PURE__ */ jsx13(Flex, { align: "center", justify: "center", height: "fill", children: /* @__PURE__ */ jsx13(Spinner, { muted: true }) }) });
1585
1701
  }
1586
1702
  return /* @__PURE__ */ jsxs9(Card, { height: "fill", tone: "transparent", children: [
1587
- /* @__PURE__ */ jsx12(Box, { padding: 5, children: /* @__PURE__ */ jsxs9(Stack, { space: 5, children: [
1703
+ /* @__PURE__ */ jsx13(Box, { padding: 5, children: /* @__PURE__ */ jsxs9(Stack, { space: 5, children: [
1588
1704
  /* @__PURE__ */ jsxs9(Flex, { align: "center", justify: "space-between", className: "dvfs-header", children: [
1589
- /* @__PURE__ */ jsx12(Heading, { size: 2, children: "Deploy with Vercel" }),
1705
+ /* @__PURE__ */ jsx13(Heading, { size: 2, children: "Deploy with Vercel" }),
1590
1706
  /* @__PURE__ */ jsxs9(Flex, { align: "center", gap: 3, className: "dvfs-header-actions", children: [
1591
- /* @__PURE__ */ jsx12(
1707
+ usesToken && /* @__PURE__ */ jsx13(
1592
1708
  Button,
1593
1709
  {
1594
1710
  text: token ? "Token connected" : "Connect API token",
@@ -1600,7 +1716,7 @@ function DeployTool() {
1600
1716
  style: { cursor: "pointer" }
1601
1717
  }
1602
1718
  ),
1603
- /* @__PURE__ */ jsx12(
1719
+ /* @__PURE__ */ jsx13(
1604
1720
  Button,
1605
1721
  {
1606
1722
  text: "Add target",
@@ -1613,12 +1729,12 @@ function DeployTool() {
1613
1729
  )
1614
1730
  ] })
1615
1731
  ] }),
1616
- !token && /* @__PURE__ */ jsx12(Card, { padding: 4, radius: 2, tone: "caution", shadow: 1, children: /* @__PURE__ */ jsxs9(Flex, { align: "center", justify: "space-between", gap: 4, children: [
1732
+ usesToken && !token && /* @__PURE__ */ jsx13(Card, { padding: 4, radius: 2, tone: "caution", shadow: 1, children: /* @__PURE__ */ jsxs9(Flex, { align: "center", justify: "space-between", gap: 4, children: [
1617
1733
  /* @__PURE__ */ jsxs9(Stack, { space: 2, children: [
1618
- /* @__PURE__ */ jsx12(Text, { size: 1, weight: "semibold", children: "Deploy status is not connected" }),
1619
- /* @__PURE__ */ jsx12(Text, { size: 1, muted: true, children: "You can trigger deploys now. Connect a Vercel API token to also see deployment status, build logs, history, and commit metadata." })
1734
+ /* @__PURE__ */ jsx13(Text, { size: 1, weight: "semibold", children: "Deploy status is not connected" }),
1735
+ /* @__PURE__ */ jsx13(Text, { size: 1, muted: true, children: "You can trigger deploys now. Connect a Vercel API token to also see deployment status, build logs, history, and commit metadata." })
1620
1736
  ] }),
1621
- /* @__PURE__ */ jsx12(
1737
+ /* @__PURE__ */ jsx13(
1622
1738
  Button,
1623
1739
  {
1624
1740
  text: "Connect",
@@ -1629,15 +1745,15 @@ function DeployTool() {
1629
1745
  }
1630
1746
  )
1631
1747
  ] }) }),
1632
- targets.length === 0 && /* @__PURE__ */ jsx12(Card, { padding: 5, radius: 2, tone: "transparent", shadow: 1, children: /* @__PURE__ */ jsxs9(Stack, { space: 4, style: { textAlign: "center" }, children: [
1633
- /* @__PURE__ */ jsx12(Text, { size: 2, weight: "semibold", children: "No deploy targets configured" }),
1748
+ targets.length === 0 && /* @__PURE__ */ jsx13(Card, { padding: 5, radius: 2, tone: "transparent", shadow: 1, children: /* @__PURE__ */ jsxs9(Stack, { space: 4, style: { textAlign: "center" }, children: [
1749
+ /* @__PURE__ */ jsx13(Text, { size: 2, weight: "semibold", children: "No deploy targets configured" }),
1634
1750
  /* @__PURE__ */ jsxs9(Text, { size: 1, muted: true, children: [
1635
1751
  "Add a deploy target using the button above, or create a",
1636
1752
  " ",
1637
- /* @__PURE__ */ jsx12("code", { children: "vercel_deploy" }),
1753
+ /* @__PURE__ */ jsx13("code", { children: "vercel_deploy" }),
1638
1754
  " document directly in the dataset."
1639
1755
  ] }),
1640
- /* @__PURE__ */ jsx12(Flex, { justify: "center", children: /* @__PURE__ */ jsx12(
1756
+ /* @__PURE__ */ jsx13(Flex, { justify: "center", children: /* @__PURE__ */ jsx13(
1641
1757
  Button,
1642
1758
  {
1643
1759
  text: "Add deploy target",
@@ -1648,12 +1764,12 @@ function DeployTool() {
1648
1764
  }
1649
1765
  ) })
1650
1766
  ] }) }),
1651
- targets.length > 0 && /* @__PURE__ */ jsx12("div", { className: "dvfs-grid", style: {
1767
+ targets.length > 0 && /* @__PURE__ */ jsx13("div", { className: "dvfs-grid", style: {
1652
1768
  display: "grid",
1653
1769
  gridTemplateColumns: "repeat(auto-fill, minmax(min(540px, 100%), 1fr))",
1654
1770
  gap: "16px",
1655
1771
  alignItems: "start"
1656
- }, children: targets.map((target) => /* @__PURE__ */ jsx12(
1772
+ }, children: targets.map((target) => /* @__PURE__ */ jsx13(
1657
1773
  DeployItem,
1658
1774
  {
1659
1775
  target,
@@ -1664,7 +1780,7 @@ function DeployTool() {
1664
1780
  target._id
1665
1781
  )) })
1666
1782
  ] }) }),
1667
- /* @__PURE__ */ jsx12(
1783
+ /* @__PURE__ */ jsx13(
1668
1784
  Box,
1669
1785
  {
1670
1786
  style: {
@@ -1681,7 +1797,7 @@ function DeployTool() {
1681
1797
  ] })
1682
1798
  }
1683
1799
  ),
1684
- showTokenSetup && /* @__PURE__ */ jsx12(
1800
+ showTokenSetup && /* @__PURE__ */ jsx13(
1685
1801
  TokenSetup,
1686
1802
  {
1687
1803
  onSaved: () => {
@@ -1692,7 +1808,7 @@ function DeployTool() {
1692
1808
  hasToken: Boolean(token)
1693
1809
  }
1694
1810
  ),
1695
- showCreateForm && /* @__PURE__ */ jsx12(
1811
+ showCreateForm && /* @__PURE__ */ jsx13(
1696
1812
  DeployTargetForm,
1697
1813
  {
1698
1814
  onSaved: () => {
@@ -1702,7 +1818,7 @@ function DeployTool() {
1702
1818
  onClose: () => setShowCreateForm(false)
1703
1819
  }
1704
1820
  ),
1705
- pendingEdit && /* @__PURE__ */ jsx12(
1821
+ pendingEdit && /* @__PURE__ */ jsx13(
1706
1822
  DeployTargetForm,
1707
1823
  {
1708
1824
  initial: pendingEdit,
@@ -1713,7 +1829,7 @@ function DeployTool() {
1713
1829
  onClose: () => setPendingEdit(null)
1714
1830
  }
1715
1831
  ),
1716
- pendingDelete && /* @__PURE__ */ jsx12(
1832
+ pendingDelete && /* @__PURE__ */ jsx13(
1717
1833
  Dialog,
1718
1834
  {
1719
1835
  header: "Delete deploy target?",
@@ -1721,7 +1837,7 @@ function DeployTool() {
1721
1837
  onClose: () => setPendingDelete(null),
1722
1838
  width: 1,
1723
1839
  footer: /* @__PURE__ */ jsxs9(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
1724
- /* @__PURE__ */ jsx12(
1840
+ /* @__PURE__ */ jsx13(
1725
1841
  Button,
1726
1842
  {
1727
1843
  text: "Cancel",
@@ -1730,7 +1846,7 @@ function DeployTool() {
1730
1846
  style: { cursor: "pointer" }
1731
1847
  }
1732
1848
  ),
1733
- /* @__PURE__ */ jsx12(
1849
+ /* @__PURE__ */ jsx13(
1734
1850
  Button,
1735
1851
  {
1736
1852
  text: "Delete",
@@ -1743,16 +1859,16 @@ function DeployTool() {
1743
1859
  }
1744
1860
  )
1745
1861
  ] }),
1746
- children: /* @__PURE__ */ jsx12(Box, { padding: 4, children: /* @__PURE__ */ jsxs9(Stack, { space: 3, children: [
1862
+ children: /* @__PURE__ */ jsx13(Box, { padding: 4, children: /* @__PURE__ */ jsxs9(Stack, { space: 3, children: [
1747
1863
  /* @__PURE__ */ jsxs9(Flex, { align: "center", gap: 2, children: [
1748
- /* @__PURE__ */ jsx12(WarningOutlineIcon, {}),
1749
- /* @__PURE__ */ jsx12(Text, { size: 2, weight: "semibold", children: pendingDelete.name })
1864
+ /* @__PURE__ */ jsx13(WarningOutlineIcon, {}),
1865
+ /* @__PURE__ */ jsx13(Text, { size: 2, weight: "semibold", children: pendingDelete.name })
1750
1866
  ] }),
1751
- /* @__PURE__ */ jsx12(Text, { size: 1, muted: true, children: "This removes the deploy target from the dataset. The Vercel deploy hook itself is not affected." })
1867
+ /* @__PURE__ */ jsx13(Text, { size: 1, muted: true, children: "This removes the deploy target from the dataset. The Vercel deploy hook itself is not affected." })
1752
1868
  ] }) })
1753
1869
  }
1754
1870
  ),
1755
- /* @__PURE__ */ jsx12(ToastViewport, {})
1871
+ /* @__PURE__ */ jsx13(ToastViewport, {})
1756
1872
  ] });
1757
1873
  }
1758
1874
 
@@ -1761,10 +1877,10 @@ import { defineField, defineType } from "sanity";
1761
1877
 
1762
1878
  // src/schema/schemaIcon.tsx
1763
1879
  import { forwardRef as forwardRef3 } from "react";
1764
- import { jsx as jsx13 } from "react/jsx-runtime";
1880
+ import { jsx as jsx14 } from "react/jsx-runtime";
1765
1881
  var SchemaRocketIcon = forwardRef3(
1766
1882
  function SchemaRocketIcon2(props, ref) {
1767
- return /* @__PURE__ */ jsx13(
1883
+ return /* @__PURE__ */ jsx14(
1768
1884
  "svg",
1769
1885
  {
1770
1886
  width: "1em",
@@ -1776,7 +1892,7 @@ var SchemaRocketIcon = forwardRef3(
1776
1892
  focusable: "false",
1777
1893
  ...props,
1778
1894
  ref,
1779
- children: /* @__PURE__ */ jsx13(
1895
+ children: /* @__PURE__ */ jsx14(
1780
1896
  "path",
1781
1897
  {
1782
1898
  d: "M12.5 20.5L15.5 14M11 9.49999L4.5 12.5M9 14C9 14 7.54688 14.9531 6.5 16C5.5 17 4.5 20.5 4.5 20.5C4.5 20.5 8 19.5 9 18.5C10 17.5 11 16 11 16M9 14C9 14 10.1 9.9 12.5 7.5C15.5 4.5 20.5 4.5 20.5 4.5C20.5 4.5 20.5 9.5 17.5 12.5C15.7492 14.2508 11 16 11 16L9 14ZM16.5 9.99999C16.5 10.8284 15.8284 11.5 15 11.5C14.1716 11.5 13.5 10.8284 13.5 9.99999C13.5 9.17157 14.1716 8.49999 15 8.49999C15.8284 8.49999 16.5 9.17157 16.5 9.99999Z",
@@ -1808,8 +1924,11 @@ var vercelDeploySchema = defineType({
1808
1924
  name: "url",
1809
1925
  title: "Deploy Hook URL",
1810
1926
  type: "url",
1811
- description: "From Vercel \u2192 Project Settings \u2192 Git \u2192 Deploy Hooks",
1812
- validation: (Rule) => Rule.required().uri({ scheme: ["https"] }).custom((url) => {
1927
+ description: "From Vercel \u2192 Project Settings \u2192 Git \u2192 Deploy Hooks. Leave empty in proxy mode and set Proxy Key instead \u2014 a hook URL is itself a deploy credential, so anyone who can read this dataset can trigger a build with it.",
1928
+ validation: (Rule) => Rule.uri({ scheme: ["https"] }).custom((url, context) => {
1929
+ const doc = context.document;
1930
+ if (!url && !doc?.proxyKey) return "Set either a Deploy Hook URL or a Proxy Key";
1931
+ if (!url) return true;
1813
1932
  if (typeof url !== "string") return true;
1814
1933
  if (!url.includes("api.vercel.com/v1/integrations/deploy/")) {
1815
1934
  return "Must be a Vercel deploy hook URL (api.vercel.com/v1/integrations/deploy/\u2026)";
@@ -1817,6 +1936,17 @@ var vercelDeploySchema = defineType({
1817
1936
  return true;
1818
1937
  })
1819
1938
  }),
1939
+ defineField({
1940
+ name: "proxyKey",
1941
+ title: "Proxy Key",
1942
+ type: "string",
1943
+ description: "Used in proxy mode. Matches a key configured on the deploy proxy, which holds the real hook URL. Contains no secret.",
1944
+ validation: (Rule) => Rule.custom((key, context) => {
1945
+ const doc = context.document;
1946
+ if (!key && !doc?.url) return "Set either a Deploy Hook URL or a Proxy Key";
1947
+ return true;
1948
+ })
1949
+ }),
1820
1950
  defineField({
1821
1951
  name: "teamId",
1822
1952
  title: "Vercel Team ID",
@@ -1836,9 +1966,11 @@ var vercelDeploySchema = defineType({
1836
1966
  }
1837
1967
  });
1838
1968
 
1839
- // src/index.ts
1969
+ // src/index.tsx
1970
+ import { jsx as jsx15 } from "react/jsx-runtime";
1840
1971
  var vercelDeploy = definePlugin((options) => {
1841
1972
  const config = options ?? {};
1973
+ const resolved = resolveConfig(options);
1842
1974
  return {
1843
1975
  name: "deploy-vercel-from-sanity",
1844
1976
  schema: {
@@ -1849,7 +1981,8 @@ var vercelDeploy = definePlugin((options) => {
1849
1981
  name: config.name ?? "vercel-deploy",
1850
1982
  title: config.title ?? "Deploy",
1851
1983
  icon: config.icon ?? RocketIcon,
1852
- component: DeployTool
1984
+ // Wrapped so the tool tree can read the resolved config without prop drilling.
1985
+ component: () => /* @__PURE__ */ jsx15(ConfigProvider, { value: resolved, children: /* @__PURE__ */ jsx15(DeployTool, {}) })
1853
1986
  }
1854
1987
  ]
1855
1988
  };