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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -27,14 +27,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // src/index.ts
30
+ // src/index.tsx
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  vercelDeploy: () => vercelDeploy,
34
34
  vercelDeploySchema: () => vercelDeploySchema
35
35
  });
36
36
  module.exports = __toCommonJS(index_exports);
37
- var import_sanity5 = require("sanity");
37
+ var import_sanity6 = require("sanity");
38
38
 
39
39
  // src/icons.tsx
40
40
  var import_react = require("react");
@@ -94,18 +94,39 @@ var TrashIcon = resolveIcon("TrashIcon", "trash");
94
94
  var WarningOutlineIcon = resolveIcon("WarningOutlineIcon", "warning-outline");
95
95
 
96
96
  // src/components/DeployTool.tsx
97
- var import_react10 = require("react");
98
- var import_sanity3 = require("sanity");
97
+ var import_react11 = require("react");
98
+ var import_sanity4 = require("sanity");
99
+
100
+ // src/config.tsx
101
+ var import_react2 = require("react");
102
+ var import_jsx_runtime2 = require("react/jsx-runtime");
103
+ var DEFAULTS = { mode: "direct" };
104
+ var ConfigContext = (0, import_react2.createContext)(DEFAULTS);
105
+ function resolveConfig(options) {
106
+ const config = options ?? {};
107
+ return {
108
+ mode: config.mode ?? "direct",
109
+ // Trailing slashes would double up when request paths are appended.
110
+ proxyUrl: config.proxyUrl?.replace(/\/+$/, ""),
111
+ statusKey: config.statusKey
112
+ };
113
+ }
114
+ function ConfigProvider({ value, children }) {
115
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ConfigContext.Provider, { value, children });
116
+ }
117
+ function usePluginConfig() {
118
+ return (0, import_react2.useContext)(ConfigContext);
119
+ }
99
120
 
100
121
  // src/components/DeployItem.tsx
101
- var import_react7 = require("react");
122
+ var import_react8 = require("react");
102
123
  var import_react_dom = require("react-dom");
103
124
 
104
125
  // src/compat/primitives.tsx
105
- var import_react2 = require("react");
106
- var import_jsx_runtime2 = require("react/jsx-runtime");
126
+ var import_react3 = require("react");
127
+ var import_jsx_runtime3 = require("react/jsx-runtime");
107
128
  function domFallback(tag) {
108
- const Fallback = (0, import_react2.forwardRef)(function SanityUiFallback(props, ref) {
129
+ const Fallback = (0, import_react3.forwardRef)(function SanityUiFallback(props, ref) {
109
130
  const { children, style, id, className, onClick, href, title, as, ...rest } = props;
110
131
  const element = typeof as === "string" ? as : tag;
111
132
  const passthrough = { style, id, className, onClick, href, title, ref };
@@ -136,7 +157,7 @@ function domFallback(tag) {
136
157
  for (const key of Object.keys(rest)) {
137
158
  if (key.startsWith("aria-") || key.startsWith("data-")) passthrough[key] = rest[key];
138
159
  }
139
- return (0, import_react2.createElement)(element, passthrough, children);
160
+ return (0, import_react3.createElement)(element, passthrough, children);
140
161
  });
141
162
  Fallback.displayName = `SanityUiFallback(${tag})`;
142
163
  return Fallback;
@@ -161,12 +182,12 @@ var Dialog = primitive("Dialog", "div");
161
182
  var SanityStack = primitive("Stack", "div");
162
183
  function Stack({ space, children, ...rest }) {
163
184
  const spacing = space === void 0 ? {} : STACK_USES_GAP ? { gap: space } : { space };
164
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SanityStack, { ...rest, ...spacing, children });
185
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SanityStack, { ...rest, ...spacing, children });
165
186
  }
166
187
 
167
188
  // src/compat/toast.tsx
168
- var import_react3 = require("react");
169
- var import_jsx_runtime3 = require("react/jsx-runtime");
189
+ var import_react4 = require("react");
190
+ var import_jsx_runtime4 = require("react/jsx-runtime");
170
191
  var LOCAL_TOAST_MS = 6e3;
171
192
  var MAX_VISIBLE_TOASTS = 4;
172
193
  var TOAST_Z_INDEX = 1e6;
@@ -221,8 +242,8 @@ function useToast() {
221
242
  return localToaster;
222
243
  }
223
244
  function ToastViewport() {
224
- const [toasts, setToasts] = (0, import_react3.useState)(localToasts);
225
- (0, import_react3.useEffect)(() => {
245
+ const [toasts, setToasts] = (0, import_react4.useState)(localToasts);
246
+ (0, import_react4.useEffect)(() => {
226
247
  if (installedUseToast) return;
227
248
  toastListeners.add(setToasts);
228
249
  setToasts(localToasts);
@@ -230,11 +251,11 @@ function ToastViewport() {
230
251
  toastListeners.delete(setToasts);
231
252
  };
232
253
  }, []);
233
- const resume = (0, import_react3.useCallback)((toast, el) => {
254
+ const resume = (0, import_react4.useCallback)((toast, el) => {
234
255
  if (el && el.contains(document.activeElement)) return;
235
256
  scheduleDismiss(toast.id, toast.status);
236
257
  }, []);
237
- const hold = (0, import_react3.useCallback)((id) => {
258
+ const hold = (0, import_react4.useCallback)((id) => {
238
259
  const timer = dismissTimers.get(id);
239
260
  if (timer) {
240
261
  clearTimeout(timer);
@@ -242,7 +263,7 @@ function ToastViewport() {
242
263
  }
243
264
  }, []);
244
265
  if (installedUseToast) return null;
245
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
266
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
246
267
  Box,
247
268
  {
248
269
  role: "log",
@@ -255,7 +276,7 @@ function ToastViewport() {
255
276
  width: "min(360px, calc(100vw - 32px))",
256
277
  pointerEvents: "none"
257
278
  },
258
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Stack, { space: 2, children: toasts.map((toast) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
279
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Stack, { space: 2, children: toasts.map((toast) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
259
280
  Card,
260
281
  {
261
282
  padding: 3,
@@ -267,12 +288,12 @@ function ToastViewport() {
267
288
  onFocusCapture: () => hold(toast.id),
268
289
  onMouseLeave: (e) => resume(toast, e.currentTarget),
269
290
  onBlurCapture: (e) => resume(toast, e.currentTarget),
270
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Flex, { align: "flex-start", gap: 3, children: [
271
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Stack, { space: 2, flex: 1, children: [
272
- toast.title && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { size: 1, weight: "semibold", children: toast.title }),
273
- toast.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { size: 1, muted: true, children: toast.description })
291
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Flex, { align: "flex-start", gap: 3, children: [
292
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Stack, { space: 2, flex: 1, children: [
293
+ toast.title && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { size: 1, weight: "semibold", children: toast.title }),
294
+ toast.description && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { size: 1, muted: true, children: toast.description })
274
295
  ] }),
275
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
296
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
276
297
  Button,
277
298
  {
278
299
  mode: "bleed",
@@ -292,17 +313,17 @@ function ToastViewport() {
292
313
  }
293
314
 
294
315
  // src/compat/tooltip.tsx
295
- var import_react4 = require("react");
296
- var import_jsx_runtime4 = require("react/jsx-runtime");
316
+ var import_react5 = require("react");
317
+ var import_jsx_runtime5 = require("react/jsx-runtime");
297
318
  var InstalledTooltip = resolveComponent(UI, "Tooltip");
298
319
  function Tooltip({ text, children }) {
299
- const id = (0, import_react4.useId)();
300
- const [visible, setVisible] = (0, import_react4.useState)(false);
320
+ const id = (0, import_react5.useId)();
321
+ const [visible, setVisible] = (0, import_react5.useState)(false);
301
322
  if (InstalledTooltip) {
302
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(InstalledTooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Box, { padding: 2, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { size: 1, children: text }) }), portal: true, children });
323
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InstalledTooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box, { padding: 2, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { size: 1, children: text }) }), portal: true, children });
303
324
  }
304
- const described = visible && (0, import_react4.isValidElement)(children) ? (0, import_react4.cloneElement)(children, { "aria-describedby": id }) : children;
305
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
325
+ const described = visible && (0, import_react5.isValidElement)(children) ? (0, import_react5.cloneElement)(children, { "aria-describedby": id }) : children;
326
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
306
327
  "span",
307
328
  {
308
329
  style: { position: "relative", display: "inline-flex" },
@@ -318,7 +339,7 @@ function Tooltip({ text, children }) {
318
339
  },
319
340
  children: [
320
341
  described,
321
- visible && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
342
+ visible && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
322
343
  "span",
323
344
  {
324
345
  id,
@@ -334,7 +355,7 @@ function Tooltip({ text, children }) {
334
355
  whiteSpace: "nowrap",
335
356
  zIndex: 1e3
336
357
  },
337
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Card, { radius: 2, shadow: 2, padding: 2, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { size: 1, children: text }) })
358
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Card, { radius: 2, shadow: 2, padding: 2, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { size: 1, children: text }) })
338
359
  }
339
360
  )
340
361
  ]
@@ -343,36 +364,36 @@ function Tooltip({ text, children }) {
343
364
  }
344
365
 
345
366
  // src/compat/menu.tsx
346
- var import_react5 = require("react");
347
- var import_jsx_runtime5 = require("react/jsx-runtime");
367
+ var import_react6 = require("react");
368
+ var import_jsx_runtime6 = require("react/jsx-runtime");
348
369
  var InstalledMenuButton = resolveComponent(UI, "MenuButton");
349
370
  var InstalledMenu = resolveComponent(UI, "Menu");
350
371
  var InstalledMenuItem = resolveComponent(UI, "MenuItem");
351
372
  var INSTALLED_MENU = InstalledMenuButton && InstalledMenu && InstalledMenuItem ? { MenuButton: InstalledMenuButton, Menu: InstalledMenu, MenuItem: InstalledMenuItem } : null;
352
373
  var itemKey = (item, index) => item.key ?? `${index}-${item.text}`;
353
374
  function ActionMenu({ id, label, items, buttonIcon }) {
354
- const menuId = (0, import_react5.useId)();
355
- const [open, setOpen] = (0, import_react5.useState)(false);
356
- const [activeIndex, setActiveIndex] = (0, import_react5.useState)(0);
357
- const wrapRef = (0, import_react5.useRef)(null);
358
- const triggerRef = (0, import_react5.useRef)(null);
359
- const itemRefs = (0, import_react5.useRef)([]);
360
- const [frozenItems, setFrozenItems] = (0, import_react5.useState)(items);
375
+ const menuId = (0, import_react6.useId)();
376
+ const [open, setOpen] = (0, import_react6.useState)(false);
377
+ const [activeIndex, setActiveIndex] = (0, import_react6.useState)(0);
378
+ const wrapRef = (0, import_react6.useRef)(null);
379
+ const triggerRef = (0, import_react6.useRef)(null);
380
+ const itemRefs = (0, import_react6.useRef)([]);
381
+ const [frozenItems, setFrozenItems] = (0, import_react6.useState)(items);
361
382
  const shownItems = open ? frozenItems : items;
362
- const close = (0, import_react5.useCallback)((returnFocus = true) => {
383
+ const close = (0, import_react6.useCallback)((returnFocus = true) => {
363
384
  setOpen(false);
364
385
  if (returnFocus) triggerRef.current?.focus();
365
386
  }, []);
366
- const openMenu = (0, import_react5.useCallback)((index) => {
387
+ const openMenu = (0, import_react6.useCallback)((index) => {
367
388
  setFrozenItems(items);
368
389
  setActiveIndex(index);
369
390
  setOpen(true);
370
391
  }, [items]);
371
- (0, import_react5.useEffect)(() => {
392
+ (0, import_react6.useEffect)(() => {
372
393
  if (!open || INSTALLED_MENU) return;
373
394
  itemRefs.current[activeIndex]?.focus();
374
395
  }, [open, activeIndex]);
375
- (0, import_react5.useEffect)(() => {
396
+ (0, import_react6.useEffect)(() => {
376
397
  if (INSTALLED_MENU || !open) return;
377
398
  const onPointerDown = (e) => {
378
399
  if (wrapRef.current?.contains(e.target)) return;
@@ -383,19 +404,19 @@ function ActionMenu({ id, label, items, buttonIcon }) {
383
404
  document.addEventListener("mousedown", onPointerDown);
384
405
  return () => document.removeEventListener("mousedown", onPointerDown);
385
406
  }, [open]);
386
- const runAction = (0, import_react5.useCallback)((item) => {
407
+ const runAction = (0, import_react6.useCallback)((item) => {
387
408
  close();
388
409
  item.onClick?.();
389
410
  }, [close]);
390
411
  if (INSTALLED_MENU) {
391
412
  const { MenuButton, Menu, MenuItem } = INSTALLED_MENU;
392
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
413
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
393
414
  MenuButton,
394
415
  {
395
416
  id,
396
- button: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Button, { mode: "ghost", icon: buttonIcon, padding: 2, "aria-label": label }),
417
+ button: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { mode: "ghost", icon: buttonIcon, padding: 2, "aria-label": label }),
397
418
  popover: { placement: "bottom-end" },
398
- menu: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Menu, { children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
419
+ menu: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Menu, { children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
399
420
  MenuItem,
400
421
  {
401
422
  text: item.text,
@@ -462,8 +483,8 @@ function ActionMenu({ id, label, items, buttonIcon }) {
462
483
  openMenu(items.length - 1);
463
484
  }
464
485
  };
465
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: wrapRef, style: { position: "relative" }, children: [
466
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
486
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: wrapRef, style: { position: "relative" }, children: [
487
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
467
488
  Button,
468
489
  {
469
490
  ref: triggerRef,
@@ -479,7 +500,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
479
500
  onKeyDown: onTriggerKeyDown
480
501
  }
481
502
  ),
482
- open && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
503
+ open && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
483
504
  Card,
484
505
  {
485
506
  id: menuId,
@@ -490,13 +511,13 @@ function ActionMenu({ id, label, items, buttonIcon }) {
490
511
  "aria-labelledby": id,
491
512
  onKeyDown: onMenuKeyDown,
492
513
  style: { position: "absolute", top: "100%", right: 0, marginTop: 4, zIndex: 1e3, minWidth: 200 },
493
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Stack, { space: 1, role: "none", children: shownItems.map((item, i) => {
514
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Stack, { space: 1, role: "none", children: shownItems.map((item, i) => {
494
515
  const Icon = item.icon;
495
- const row = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Flex, { align: "center", gap: 2, paddingX: 2, paddingY: 2, children: [
496
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { width: "1em", height: "1em", "aria-hidden": "true" }),
497
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { size: 1, children: item.text })
516
+ const row = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Flex, { align: "center", gap: 2, paddingX: 2, paddingY: 2, children: [
517
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { width: "1em", height: "1em", "aria-hidden": "true" }),
518
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { size: 1, children: item.text })
498
519
  ] });
499
- const content = item.tone === "critical" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Card, { tone: "critical", radius: 1, children: row }) : row;
520
+ const content = item.tone === "critical" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Card, { tone: "critical", radius: 1, children: row }) : row;
500
521
  const shared = {
501
522
  role: "menuitem",
502
523
  // Roving tabindex — the menu is one tab stop, arrows move within it.
@@ -521,7 +542,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
521
542
  outlineOffset: -2
522
543
  }
523
544
  };
524
- return item.href ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
545
+ return item.href ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
525
546
  "a",
526
547
  {
527
548
  ...shared,
@@ -535,7 +556,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
535
556
  children: content
536
557
  },
537
558
  itemKey(item, i)
538
- ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
559
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
539
560
  "div",
540
561
  {
541
562
  ...shared,
@@ -551,7 +572,7 @@ function ActionMenu({ id, label, items, buttonIcon }) {
551
572
  }
552
573
 
553
574
  // src/compat/code.tsx
554
- var import_jsx_runtime6 = require("react/jsx-runtime");
575
+ var import_jsx_runtime7 = require("react/jsx-runtime");
555
576
  var InstalledCode = resolveComponent(UI, "Code");
556
577
  var FALLBACK_CODE_STYLE = {
557
578
  display: "block",
@@ -561,8 +582,8 @@ var FALLBACK_CODE_STYLE = {
561
582
  margin: 0
562
583
  };
563
584
  function Code({ style, children }) {
564
- if (InstalledCode) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(InstalledCode, { size: 1, style, children });
565
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { style: { ...FALLBACK_CODE_STYLE, ...style }, children });
585
+ if (InstalledCode) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(InstalledCode, { size: 1, style, children });
586
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { style: { ...FALLBACK_CODE_STYLE, ...style }, children });
566
587
  }
567
588
 
568
589
  // src/lib/api.ts
@@ -578,7 +599,7 @@ async function vercelFetch(path, token, init) {
578
599
  }
579
600
  });
580
601
  if (!res.ok) {
581
- 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." : "";
602
+ 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." : "";
582
603
  throw new Error(`Vercel API ${res.status}${hint}`);
583
604
  }
584
605
  return res.json();
@@ -617,15 +638,75 @@ async function getDeploymentEvents(opts) {
617
638
  const params = new URLSearchParams({ limit: "100", direction: "backward" });
618
639
  if (opts.teamId) params.set("teamId", opts.teamId);
619
640
  const raw = await vercelFetch(
620
- `/v2/deployments/${opts.deploymentId}/events?${params}`,
641
+ `/v2/deployments/${encodeURIComponent(opts.deploymentId)}/events?${params}`,
621
642
  opts.token
622
643
  );
623
644
  const events = Array.isArray(raw) ? raw : raw.events ?? [];
624
645
  return events.filter((e) => e.text?.trim());
625
646
  }
626
647
 
648
+ // src/lib/transport.ts
649
+ async function proxyFetch(url, statusKey, init) {
650
+ const res = await fetch(url, {
651
+ ...init,
652
+ headers: {
653
+ "Content-Type": "application/json",
654
+ ...statusKey ? { "x-deploy-status-key": statusKey } : {},
655
+ ...init?.headers
656
+ }
657
+ });
658
+ if (!res.ok) {
659
+ 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." : "";
660
+ throw new Error(`Deploy proxy ${res.status}${hint}`);
661
+ }
662
+ return res.json();
663
+ }
664
+ async function fetchDeployments(transport, target, limit) {
665
+ if (transport.mode === "direct") {
666
+ if (!target.projectId || !target.hookId) return [];
667
+ return listDeployments({
668
+ projectId: target.projectId,
669
+ hookId: target.hookId,
670
+ token: transport.token,
671
+ teamId: target.teamId,
672
+ limit
673
+ });
674
+ }
675
+ const params = new URLSearchParams({ key: target.proxyKey ?? "" });
676
+ if (limit) params.set("limit", String(limit));
677
+ const data = await proxyFetch(
678
+ `${transport.proxyUrl}/deployments?${params}`,
679
+ transport.statusKey
680
+ );
681
+ return data.deployments ?? [];
682
+ }
683
+ async function cancelDeploy(transport, target, deploymentId) {
684
+ if (transport.mode === "direct") {
685
+ return cancelDeployment({ deploymentId, token: transport.token, teamId: target.teamId });
686
+ }
687
+ await proxyFetch(`${transport.proxyUrl}/cancel`, transport.statusKey, {
688
+ method: "POST",
689
+ body: JSON.stringify({ key: target.proxyKey, deploymentId })
690
+ });
691
+ }
692
+ async function fetchDeploymentEvents(transport, target, deploymentId) {
693
+ if (transport.mode === "direct") {
694
+ return getDeploymentEvents({ deploymentId, token: transport.token, teamId: target.teamId });
695
+ }
696
+ const params = new URLSearchParams({ key: target.proxyKey ?? "", deploymentId });
697
+ const data = await proxyFetch(
698
+ `${transport.proxyUrl}/events?${params}`,
699
+ transport.statusKey
700
+ );
701
+ return data.events ?? [];
702
+ }
703
+
704
+ // src/components/DeployItem.tsx
705
+ var import_sanity = require("sanity");
706
+
627
707
  // src/lib/helpers.ts
628
708
  function parseHookUrl(url) {
709
+ if (!url) return { projectId: "", hookId: "" };
629
710
  try {
630
711
  const path = new URL(url).pathname;
631
712
  const parts = path.split("/").filter(Boolean);
@@ -715,30 +796,33 @@ function projectHref(inspectorUrl) {
715
796
  }
716
797
 
717
798
  // src/components/StatusBadge.tsx
718
- var import_jsx_runtime7 = require("react/jsx-runtime");
799
+ var import_jsx_runtime8 = require("react/jsx-runtime");
719
800
  function StatusBadge({ state, showSpinner }) {
720
801
  const { label, tone } = stateLabel(state);
721
802
  const spinning = showSpinner && (state === "QUEUED" || state === "INITIALIZING" || state === "BUILDING");
722
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Flex, { align: "center", gap: 2, children: [
723
- spinning && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Spinner, { muted: true }),
724
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { tone, padding: 2, children: label })
803
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Flex, { align: "center", gap: 2, children: [
804
+ spinning && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Spinner, { muted: true }),
805
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Badge, { tone, padding: 2, children: label })
725
806
  ] });
726
807
  }
727
808
 
728
809
  // src/components/DeployHistory.tsx
729
- var import_react6 = require("react");
730
- var import_jsx_runtime8 = require("react/jsx-runtime");
810
+ var import_react7 = require("react");
811
+ var import_jsx_runtime9 = require("react/jsx-runtime");
731
812
  function DeployHistory({ target, token, onClose }) {
732
- const dialogId = (0, import_react6.useId)();
733
- const [deployments, setDeployments] = (0, import_react6.useState)([]);
734
- const [loading, setLoading] = (0, import_react6.useState)(true);
735
- const [error, setError] = (0, import_react6.useState)(null);
813
+ const dialogId = (0, import_react7.useId)();
814
+ const pluginConfig = usePluginConfig();
815
+ const [deployments, setDeployments] = (0, import_react7.useState)([]);
816
+ const [loading, setLoading] = (0, import_react7.useState)(true);
817
+ const [error, setError] = (0, import_react7.useState)(null);
736
818
  const { projectId, hookId } = parseHookUrl(target.url);
737
- const load = (0, import_react6.useCallback)(async () => {
819
+ const transport = pluginConfig.mode === "proxy" ? { mode: "proxy", proxyUrl: pluginConfig.proxyUrl ?? "", statusKey: pluginConfig.statusKey } : { mode: "direct", token };
820
+ const targetRef = { projectId, hookId, proxyKey: target.proxyKey, teamId: target.teamId };
821
+ const load = (0, import_react7.useCallback)(async () => {
738
822
  setLoading(true);
739
823
  setError(null);
740
824
  try {
741
- const data = await listDeployments({ projectId, hookId, token, teamId: target.teamId, limit: 10 });
825
+ const data = await fetchDeployments(transport, targetRef, 20);
742
826
  setDeployments(data);
743
827
  } catch (err) {
744
828
  setError(err instanceof Error ? err.message : "Failed to load history");
@@ -746,55 +830,55 @@ function DeployHistory({ target, token, onClose }) {
746
830
  setLoading(false);
747
831
  }
748
832
  }, [projectId, hookId, token, target.teamId]);
749
- (0, import_react6.useEffect)(() => {
833
+ (0, import_react7.useEffect)(() => {
750
834
  load();
751
835
  }, [load]);
752
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
836
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
753
837
  Dialog,
754
838
  {
755
839
  header: `${target.name} \u2014 Deployment History`,
756
840
  id: dialogId,
757
841
  onClose,
758
842
  width: 2,
759
- footer: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { padding: 3, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { text: "Close", icon: CloseIcon, mode: "ghost", onClick: onClose }) }),
760
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box, { padding: 4, children: [
761
- loading && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Flex, { justify: "center", padding: 6, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Spinner, { muted: true }) }),
762
- error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Card, { tone: "critical", padding: 4, radius: 2, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 1, children: error }) }),
763
- !loading && !error && deployments.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Card, { tone: "transparent", padding: 4, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 1, muted: true, align: "center", children: "No deployments found for this hook." }) }),
764
- !loading && deployments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Stack, { space: 2, children: [
765
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Flex, { gap: 3, children: [
766
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { flex: 2, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Preview URL" }) }),
767
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Status" }) }),
768
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { flex: 2, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Branch \xB7 Commit" }) }),
769
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Deployed" }) }),
770
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { style: { width: 64 }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Logs" }) })
843
+ footer: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { padding: 3, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Button, { text: "Close", icon: CloseIcon, mode: "ghost", onClick: onClose }) }),
844
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box, { padding: 4, children: [
845
+ loading && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Flex, { justify: "center", padding: 6, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Spinner, { muted: true }) }),
846
+ error && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Card, { tone: "critical", padding: 4, radius: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children: error }) }),
847
+ !loading && !error && deployments.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Card, { tone: "transparent", padding: 4, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, align: "center", children: "No deployments found for this hook." }) }),
848
+ !loading && deployments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 2, children: [
849
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Card, { padding: 3, radius: 2, tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 3, children: [
850
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Preview URL" }) }),
851
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Status" }) }),
852
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Branch \xB7 Commit" }) }),
853
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Deployed" }) }),
854
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { style: { width: 64 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, weight: "semibold", muted: true, children: "Logs" }) })
771
855
  ] }) }),
772
856
  deployments.map((d) => {
773
857
  const { label, tone } = stateLabel(d.state);
774
858
  const branch = d.meta?.githubCommitRef ?? "\u2014";
775
859
  const sha = shortSha(d.meta?.githubCommitSha);
776
860
  const message = d.meta?.githubCommitMessage?.split("\n")[0] ?? "";
777
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Card, { padding: 3, radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Flex, { gap: 3, align: "center", children: [
778
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { flex: 2, style: { overflow: "hidden" }, children: deploymentHref(d.url) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
861
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Card, { padding: 3, radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 3, align: "center", children: [
862
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 2, style: { overflow: "hidden" }, children: deploymentHref(d.url) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
779
863
  "a",
780
864
  {
781
865
  href: deploymentHref(d.url),
782
866
  target: "_blank",
783
867
  rel: "noreferrer",
784
868
  style: { color: "inherit" },
785
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 1, style: { textDecoration: "underline" }, children: d.url.length > 36 ? `${d.url.slice(0, 36)}\u2026` : d.url })
869
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, style: { textDecoration: "underline" }, children: d.url.length > 36 ? `${d.url.slice(0, 36)}\u2026` : d.url })
786
870
  }
787
- ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 1, muted: true, children: "\u2014" }) }),
788
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Badge, { tone, children: label }) }),
789
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { flex: 2, style: { overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Stack, { space: 1, children: [
790
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 1, children: branch }),
791
- sha && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { size: 0, muted: true, children: [
871
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: "\u2014" }) }),
872
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Badge, { tone, children: label }) }),
873
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 2, style: { overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 1, children: [
874
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children: branch }),
875
+ sha && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { size: 0, muted: true, children: [
792
876
  sha,
793
877
  message ? ` \xB7 ${message.slice(0, 40)}${message.length > 40 ? "\u2026" : ""}` : ""
794
878
  ] })
795
879
  ] }) }),
796
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 1, muted: true, children: timeAgo(d.created) }) }),
797
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { style: { width: 64 }, children: safeHref(d.inspectorUrl) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
880
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: timeAgo(d.created) }) }),
881
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { style: { width: 64 }, children: safeHref(d.inspectorUrl) ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
798
882
  Button,
799
883
  {
800
884
  as: "a",
@@ -807,7 +891,7 @@ function DeployHistory({ target, token, onClose }) {
807
891
  icon: LaunchIcon,
808
892
  style: { fontSize: "12px" }
809
893
  }
810
- ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { size: 1, muted: true, children: "\u2014" }) })
894
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: "\u2014" }) })
811
895
  ] }) }, d.uid);
812
896
  })
813
897
  ] })
@@ -817,31 +901,35 @@ function DeployHistory({ target, token, onClose }) {
817
901
  }
818
902
 
819
903
  // src/components/DeployItem.tsx
820
- var import_jsx_runtime9 = require("react/jsx-runtime");
904
+ var import_jsx_runtime10 = require("react/jsx-runtime");
821
905
  var POLL_INTERVAL_MS = 5e3;
822
906
  var LABEL_WIDTH = 64;
823
907
  var PENDING_TIMEOUT_MS = 6e4;
824
908
  function DeployItem({ target, token, onDelete, onEdit }) {
825
909
  const { projectId, hookId } = parseHookUrl(target.url);
826
910
  const toast = useToast();
827
- const [deployments, setDeployments] = (0, import_react7.useState)([]);
828
- const [loadingInitial, setLoadingInitial] = (0, import_react7.useState)(true);
829
- const [pendingSince, setPendingSince] = (0, import_react7.useState)(null);
830
- const [canceling, setCanceling] = (0, import_react7.useState)(false);
831
- const [deployError, setDeployError] = (0, import_react7.useState)(null);
832
- const [showHistory, setShowHistory] = (0, import_react7.useState)(false);
833
- const [elapsed, setElapsed] = (0, import_react7.useState)(0);
834
- const [copied, setCopied] = (0, import_react7.useState)(false);
835
- const [showDetails, setShowDetails] = (0, import_react7.useState)(false);
836
- const [showErrorLogs, setShowErrorLogs] = (0, import_react7.useState)(false);
837
- const [errorLines, setErrorLines] = (0, import_react7.useState)([]);
838
- const [loadingLogs, setLoadingLogs] = (0, import_react7.useState)(false);
839
- const [logError, setLogError] = (0, import_react7.useState)(null);
840
- const [pollError, setPollError] = (0, import_react7.useState)(null);
841
- const triggeredFromUidRef = (0, import_react7.useRef)(void 0);
842
- const requestSeqRef = (0, import_react7.useRef)(0);
843
- const mountedRef = (0, import_react7.useRef)(true);
844
- (0, import_react7.useEffect)(() => {
911
+ const pluginConfig = usePluginConfig();
912
+ const client = (0, import_sanity.useClient)({ apiVersion: "2025-01-01" });
913
+ const transport = pluginConfig.mode === "proxy" ? { mode: "proxy", proxyUrl: pluginConfig.proxyUrl ?? "", statusKey: pluginConfig.statusKey } : { mode: "direct", token };
914
+ const targetRef = { projectId, hookId, proxyKey: target.proxyKey, teamId: target.teamId };
915
+ const [deployments, setDeployments] = (0, import_react8.useState)([]);
916
+ const [loadingInitial, setLoadingInitial] = (0, import_react8.useState)(true);
917
+ const [pendingSince, setPendingSince] = (0, import_react8.useState)(null);
918
+ const [canceling, setCanceling] = (0, import_react8.useState)(false);
919
+ const [deployError, setDeployError] = (0, import_react8.useState)(null);
920
+ const [showHistory, setShowHistory] = (0, import_react8.useState)(false);
921
+ const [elapsed, setElapsed] = (0, import_react8.useState)(0);
922
+ const [copied, setCopied] = (0, import_react8.useState)(false);
923
+ const [showDetails, setShowDetails] = (0, import_react8.useState)(false);
924
+ const [showErrorLogs, setShowErrorLogs] = (0, import_react8.useState)(false);
925
+ const [errorLines, setErrorLines] = (0, import_react8.useState)([]);
926
+ const [loadingLogs, setLoadingLogs] = (0, import_react8.useState)(false);
927
+ const [logError, setLogError] = (0, import_react8.useState)(null);
928
+ const [pollError, setPollError] = (0, import_react8.useState)(null);
929
+ const triggeredFromUidRef = (0, import_react8.useRef)(void 0);
930
+ const requestSeqRef = (0, import_react8.useRef)(0);
931
+ const mountedRef = (0, import_react8.useRef)(true);
932
+ (0, import_react8.useEffect)(() => {
845
933
  mountedRef.current = true;
846
934
  return () => {
847
935
  mountedRef.current = false;
@@ -850,11 +938,12 @@ function DeployItem({ target, token, onDelete, onEdit }) {
850
938
  const latest = deployments[0];
851
939
  const isPending = pendingSince !== null;
852
940
  const isActive = isPending || isActiveState(latest?.state);
853
- const fetchDeployments = (0, import_react7.useCallback)(async () => {
854
- if (!projectId || !hookId || !token) return;
941
+ const fetchDeployments2 = (0, import_react8.useCallback)(async () => {
942
+ const ready = transport.mode === "proxy" ? Boolean(target.proxyKey && pluginConfig.proxyUrl) : Boolean(projectId && hookId && token);
943
+ if (!ready) return;
855
944
  const seq = ++requestSeqRef.current;
856
945
  try {
857
- const data = await listDeployments({ projectId, hookId, token, teamId: target.teamId });
946
+ const data = await fetchDeployments(transport, targetRef);
858
947
  if (seq !== requestSeqRef.current || !mountedRef.current) return;
859
948
  setDeployments(data);
860
949
  setPollError(null);
@@ -863,26 +952,26 @@ function DeployItem({ target, token, onDelete, onEdit }) {
863
952
  setPollError(err instanceof Error ? err.message : "Could not reach the Vercel API");
864
953
  console.error("Deploy-vercel-from-sanity: fetch error", err);
865
954
  }
866
- }, [projectId, hookId, token, target.teamId]);
867
- (0, import_react7.useEffect)(() => {
868
- fetchDeployments().finally(() => setLoadingInitial(false));
869
- }, [fetchDeployments]);
870
- (0, import_react7.useEffect)(() => {
955
+ }, [projectId, hookId, token, target.teamId, target.proxyKey, transport.mode, pluginConfig.proxyUrl]);
956
+ (0, import_react8.useEffect)(() => {
957
+ fetchDeployments2().finally(() => setLoadingInitial(false));
958
+ }, [fetchDeployments2]);
959
+ (0, import_react8.useEffect)(() => {
871
960
  if (!isActive) return;
872
- const id = setInterval(fetchDeployments, POLL_INTERVAL_MS);
961
+ const id = setInterval(fetchDeployments2, POLL_INTERVAL_MS);
873
962
  return () => clearInterval(id);
874
- }, [isActive, fetchDeployments]);
875
- (0, import_react7.useEffect)(() => {
963
+ }, [isActive, fetchDeployments2]);
964
+ (0, import_react8.useEffect)(() => {
876
965
  if (!isPending) return;
877
966
  if (latest?.uid && latest.uid !== triggeredFromUidRef.current) setPendingSince(null);
878
967
  }, [isPending, latest?.uid]);
879
- (0, import_react7.useEffect)(() => {
968
+ (0, import_react8.useEffect)(() => {
880
969
  if (!isPending) return;
881
970
  const id = setTimeout(() => setPendingSince(null), PENDING_TIMEOUT_MS);
882
971
  return () => clearTimeout(id);
883
972
  }, [isPending]);
884
- const prevStateRef = (0, import_react7.useRef)(void 0);
885
- (0, import_react7.useEffect)(() => {
973
+ const prevStateRef = (0, import_react8.useRef)(void 0);
974
+ (0, import_react8.useEffect)(() => {
886
975
  const current = latest?.state;
887
976
  const prev = prevStateRef.current;
888
977
  if (prev && isActiveState(prev) && current && !isActiveState(current)) {
@@ -896,13 +985,13 @@ function DeployItem({ target, token, onDelete, onEdit }) {
896
985
  }
897
986
  prevStateRef.current = current;
898
987
  }, [latest?.state, target.name, toast]);
899
- (0, import_react7.useEffect)(() => {
988
+ (0, import_react8.useEffect)(() => {
900
989
  setShowErrorLogs(false);
901
990
  setErrorLines([]);
902
991
  setLogError(null);
903
992
  }, [latest?.uid]);
904
- const timerRef = (0, import_react7.useRef)(null);
905
- (0, import_react7.useEffect)(() => {
993
+ const timerRef = (0, import_react8.useRef)(null);
994
+ (0, import_react8.useEffect)(() => {
906
995
  if (isActive) {
907
996
  const start = pendingSince ?? latest?.created ?? Date.now();
908
997
  setElapsed(Math.floor((Date.now() - start) / 1e3));
@@ -917,7 +1006,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
917
1006
  if (timerRef.current) clearInterval(timerRef.current);
918
1007
  };
919
1008
  }, [isActive, pendingSince, latest?.created]);
920
- const deploy = (0, import_react7.useCallback)(() => {
1009
+ const deploy = (0, import_react8.useCallback)(() => {
921
1010
  (0, import_react_dom.flushSync)(() => {
922
1011
  setDeployError(null);
923
1012
  triggeredFromUidRef.current = latest?.uid;
@@ -925,27 +1014,37 @@ function DeployItem({ target, token, onDelete, onEdit }) {
925
1014
  });
926
1015
  void (async () => {
927
1016
  try {
928
- await triggerDeploy(target.url);
929
- setTimeout(fetchDeployments, 2e3);
1017
+ if (pluginConfig.mode === "proxy") {
1018
+ if (!target.proxyKey) throw new Error("Target has no proxy key \u2014 set one on the deploy target");
1019
+ await client.create({
1020
+ _type: "vercelDeploy.request",
1021
+ target: { _type: "reference", _ref: target._id },
1022
+ proxyKey: target.proxyKey,
1023
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString()
1024
+ });
1025
+ } else {
1026
+ await triggerDeploy(target.url ?? "");
1027
+ }
1028
+ setTimeout(fetchDeployments2, 2e3);
930
1029
  } catch (err) {
931
1030
  setPendingSince(null);
932
1031
  setDeployError(err instanceof Error ? err.message : "Deploy failed");
933
1032
  }
934
1033
  })();
935
- }, [target.url, fetchDeployments, latest?.uid]);
936
- const cancel = (0, import_react7.useCallback)(async () => {
1034
+ }, [target.url, target.proxyKey, target._id, pluginConfig.mode, client, fetchDeployments2, latest?.uid]);
1035
+ const cancel = (0, import_react8.useCallback)(async () => {
937
1036
  if (!latest?.uid) return;
938
1037
  setCanceling(true);
939
1038
  try {
940
- await cancelDeployment({ deploymentId: latest.uid, token, teamId: target.teamId });
941
- await fetchDeployments();
1039
+ await cancelDeploy(transport, targetRef, latest.uid);
1040
+ await fetchDeployments2();
942
1041
  } catch (err) {
943
1042
  console.error("deploy-vercel-from-sanity: cancel error", err);
944
1043
  } finally {
945
1044
  setCanceling(false);
946
1045
  }
947
- }, [latest?.uid, token, target.teamId, fetchDeployments]);
948
- const copyUrl = (0, import_react7.useCallback)(() => {
1046
+ }, [latest?.uid, token, target.teamId, fetchDeployments2]);
1047
+ const copyUrl = (0, import_react8.useCallback)(() => {
949
1048
  if (!latest?.url) return;
950
1049
  const fullUrl = deploymentHref(latest.url) ?? "";
951
1050
  navigator.clipboard.writeText(fullUrl).then(() => {
@@ -955,16 +1054,12 @@ function DeployItem({ target, token, onDelete, onEdit }) {
955
1054
  window.prompt("Copy deployment URL:", fullUrl);
956
1055
  });
957
1056
  }, [latest?.url]);
958
- const fetchErrorLogs = (0, import_react7.useCallback)(async () => {
1057
+ const fetchErrorLogs = (0, import_react8.useCallback)(async () => {
959
1058
  if (!latest?.uid) return;
960
1059
  setLoadingLogs(true);
961
1060
  setLogError(null);
962
1061
  try {
963
- const events = await getDeploymentEvents({
964
- deploymentId: latest.uid,
965
- token,
966
- teamId: target.teamId
967
- });
1062
+ const events = await fetchDeploymentEvents(transport, targetRef, latest.uid);
968
1063
  const lines = events.filter((e) => e.type === "stderr" || e.type === "stdout").map((e) => e.text ?? "").filter(Boolean).reverse().slice(-30);
969
1064
  setErrorLines(lines.length > 0 ? lines : ["No stderr or stdout was captured for this build. Open the full build log in Vercel for details."]);
970
1065
  } catch (err) {
@@ -973,7 +1068,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
973
1068
  setLoadingLogs(false);
974
1069
  }
975
1070
  }, [latest?.uid, token, target.teamId]);
976
- const toggleErrorLogs = (0, import_react7.useCallback)(() => {
1071
+ const toggleErrorLogs = (0, import_react8.useCallback)(() => {
977
1072
  if (!showErrorLogs && errorLines.length === 0 && !logError) fetchErrorLogs();
978
1073
  setShowErrorLogs((v) => !v);
979
1074
  }, [showErrorLogs, errorLines.length, logError, fetchErrorLogs]);
@@ -986,20 +1081,20 @@ function DeployItem({ target, token, onDelete, onEdit }) {
986
1081
  const deployedAt = latest?.created ? timeAgo(latest.created) : null;
987
1082
  const vercelProjectUrl = projectHref(latest?.inspectorUrl);
988
1083
  const isError = latest?.state === "ERROR";
989
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
990
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Card, { radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "stretch", className: "dvfs-card-flex", children: [
991
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { direction: "column", flex: 1, style: { minWidth: 0 }, children: [
992
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 3, padding: 3, style: { flex: 1 }, children: [
993
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", justify: "space-between", gap: 2, children: [
994
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 2, style: { minWidth: 0, flexWrap: "wrap" }, children: [
995
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 2, weight: "semibold", style: { flexShrink: 0 }, children: target.name }),
996
- branch && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Badge, { tone: "default", padding: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 1, children: [
1084
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1085
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Card, { radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "stretch", className: "dvfs-card-flex", children: [
1086
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { direction: "column", flex: 1, style: { minWidth: 0 }, children: [
1087
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 3, padding: 3, style: { flex: 1 }, children: [
1088
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", justify: "space-between", gap: 2, children: [
1089
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 2, style: { minWidth: 0, flexWrap: "wrap" }, children: [
1090
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 2, weight: "semibold", style: { flexShrink: 0 }, children: target.name }),
1091
+ branch && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Badge, { tone: "default", padding: 2, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 1, children: [
997
1092
  branch,
998
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", style: { marginLeft: "-0.1em", opacity: 0.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("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" }) })
1093
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", style: { marginLeft: "-0.1em", opacity: 0.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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" }) })
999
1094
  ] }) }),
1000
- token && !loadingInitial && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1001
- isPending ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StatusBadge, { state: "QUEUED" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StatusBadge, { state: latest?.state }),
1002
- isActiveState(latest?.state) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1095
+ token && !loadingInitial && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1096
+ isPending ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatusBadge, { state: "QUEUED" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatusBadge, { state: latest?.state }),
1097
+ isActiveState(latest?.state) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1003
1098
  Button,
1004
1099
  {
1005
1100
  text: "Cancel",
@@ -1013,14 +1108,14 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1013
1108
  ),
1014
1109
  isPending ? (
1015
1110
  /* Optimistic — dimmed spinner only; no elapsed time until a real build exists */
1016
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Spinner, { muted: true, style: { marginLeft: 4, opacity: 0.5 } })
1017
- ) : isActive ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 1, children: [
1018
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Spinner, { muted: true, style: { marginLeft: 4 } }),
1019
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: formatDuration(elapsed) })
1020
- ] }) : deployedAt ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: deployedAt }) : null
1111
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner, { muted: true, style: { marginLeft: 4, opacity: 0.5 } })
1112
+ ) : isActive ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 1, children: [
1113
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner, { muted: true, style: { marginLeft: 4 } }),
1114
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, muted: true, children: formatDuration(elapsed) })
1115
+ ] }) : deployedAt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, muted: true, children: deployedAt }) : null
1021
1116
  ] })
1022
1117
  ] }),
1023
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1118
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1024
1119
  ActionMenu,
1025
1120
  {
1026
1121
  id: `menu-${target._id}`,
@@ -1036,43 +1131,43 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1036
1131
  }
1037
1132
  )
1038
1133
  ] }),
1039
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("hr", { style: { border: "none", borderTop: "1px solid currentColor", opacity: 0.1, margin: 0 } }),
1040
- !token ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: "Connect a Vercel API token to see deployment status." }) : loadingInitial ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 2, children: [
1041
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Spinner, { muted: true }),
1042
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: "Loading\u2026" })
1043
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 2, children: [
1044
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 2, wrap: "wrap", children: [
1045
- latest?.url && latest.state === "READY" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1134
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("hr", { style: { border: "none", borderTop: "1px solid currentColor", opacity: 0.1, margin: 0 } }),
1135
+ !token ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(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__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 2, children: [
1136
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner, { muted: true }),
1137
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, muted: true, children: "Loading\u2026" })
1138
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 2, children: [
1139
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 2, wrap: "wrap", children: [
1140
+ latest?.url && latest.state === "READY" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1046
1141
  "a",
1047
1142
  {
1048
1143
  href: deploymentHref(latest.url),
1049
1144
  target: "_blank",
1050
1145
  rel: "noreferrer",
1051
1146
  style: { color: "inherit" },
1052
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children: latest.url }) })
1147
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Flex, { align: "center", gap: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, children: latest.url }) })
1053
1148
  }
1054
1149
  ) }),
1055
- sha && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Tooltip, { text: commitMsg ?? sha, children: commitHref ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1150
+ sha && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Tooltip, { text: commitMsg ?? sha, children: commitHref ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1056
1151
  "a",
1057
1152
  {
1058
1153
  href: commitHref,
1059
1154
  target: "_blank",
1060
1155
  rel: "noreferrer",
1061
1156
  style: { color: "inherit", textDecoration: "none" },
1062
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, style: { cursor: "pointer", fontFamily: "monospace" }, children: sha })
1157
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, muted: true, style: { cursor: "pointer", fontFamily: "monospace" }, children: sha })
1063
1158
  }
1064
- ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, style: { cursor: "default", fontFamily: "monospace" }, children: sha }) }),
1065
- creator && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { size: 1, muted: true, children: [
1159
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, muted: true, style: { cursor: "default", fontFamily: "monospace" }, children: sha }) }),
1160
+ creator && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { size: 1, muted: true, children: [
1066
1161
  "by ",
1067
1162
  creator
1068
1163
  ] }),
1069
- latest?.state === "READY" && latest.ready && latest.created && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { size: 1, muted: true, children: [
1164
+ latest?.state === "READY" && latest.ready && latest.created && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { size: 1, muted: true, children: [
1070
1165
  "Took ",
1071
1166
  formatDuration(Math.floor((latest.ready - latest.created) / 1e3)),
1072
1167
  " to build"
1073
1168
  ] }),
1074
- latest?.url && latest.state === "READY" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1075
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Tooltip, { text: copied ? "Copied" : "Copy deployment URL", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1169
+ latest?.url && latest.state === "READY" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1170
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Tooltip, { text: copied ? "Copied" : "Copy deployment URL", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1076
1171
  Button,
1077
1172
  {
1078
1173
  mode: "ghost",
@@ -1084,7 +1179,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1084
1179
  style: { cursor: "pointer" }
1085
1180
  }
1086
1181
  ) }),
1087
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1182
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1088
1183
  "span",
1089
1184
  {
1090
1185
  role: "status",
@@ -1102,8 +1197,8 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1102
1197
  )
1103
1198
  ] })
1104
1199
  ] }),
1105
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 2, wrap: "wrap", children: [
1106
- commitMsg && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1200
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 2, wrap: "wrap", children: [
1201
+ commitMsg && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1107
1202
  Text,
1108
1203
  {
1109
1204
  size: 0,
@@ -1112,8 +1207,8 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1112
1207
  children: commitMsg
1113
1208
  }
1114
1209
  ),
1115
- isError && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 2, children: [
1116
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1210
+ isError && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 2, children: [
1211
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1117
1212
  Button,
1118
1213
  {
1119
1214
  "aria-expanded": showErrorLogs,
@@ -1127,40 +1222,40 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1127
1222
  style: { alignSelf: "flex-start", cursor: "pointer" }
1128
1223
  }
1129
1224
  ),
1130
- showErrorLogs && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Card, { tone: "critical", radius: 2, padding: 3, children: [
1131
- loadingLogs && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 2, children: [
1132
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Spinner, { muted: true }),
1133
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: "Loading logs\u2026" })
1225
+ showErrorLogs && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Card, { tone: "critical", radius: 2, padding: 3, children: [
1226
+ loadingLogs && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 2, children: [
1227
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner, { muted: true }),
1228
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, muted: true, children: "Loading logs\u2026" })
1134
1229
  ] }),
1135
- logError && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 2, children: [
1136
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children: logError }),
1137
- safeHref(latest?.inspectorUrl) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 1, children: [
1138
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LaunchIcon, {}),
1139
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children: "View full logs in Vercel" })
1230
+ logError && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 2, children: [
1231
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, children: logError }),
1232
+ safeHref(latest?.inspectorUrl) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 1, children: [
1233
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LaunchIcon, {}),
1234
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, children: "View full logs in Vercel" })
1140
1235
  ] }) })
1141
1236
  ] }),
1142
- !loadingLogs && !logError && errorLines.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 2, children: [
1143
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { style: { maxHeight: 240, overflowY: "auto", fontFamily: "monospace", fontSize: 13, lineHeight: 1.6 }, children: errorLines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Code, { style: { display: "block", whiteSpace: "pre-wrap", wordBreak: "break-all" }, children: line }, i)) }),
1144
- safeHref(latest?.inspectorUrl) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 1, children: [
1145
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LaunchIcon, {}),
1146
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children: "View full logs in Vercel" })
1237
+ !loadingLogs && !logError && errorLines.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 2, children: [
1238
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box, { style: { maxHeight: 240, overflowY: "auto", fontFamily: "monospace", fontSize: 13, lineHeight: 1.6 }, children: errorLines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Code, { style: { display: "block", whiteSpace: "pre-wrap", wordBreak: "break-all" }, children: line }, i)) }),
1239
+ safeHref(latest?.inspectorUrl) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 1, children: [
1240
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LaunchIcon, {}),
1241
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, children: "View full logs in Vercel" })
1147
1242
  ] }) })
1148
1243
  ] })
1149
1244
  ] })
1150
1245
  ] }),
1151
- deployError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Card, { tone: "critical", padding: 2, radius: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children: deployError }) })
1246
+ deployError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Card, { tone: "critical", padding: 2, radius: 2, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, children: deployError }) })
1152
1247
  ] })
1153
1248
  ] }),
1154
- pollError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Card, { tone: "caution", padding: 3, radius: 2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 2, children: [
1155
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(WarningOutlineIcon, { "aria-hidden": "true" }),
1156
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { size: 1, children: [
1249
+ pollError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Card, { tone: "caution", padding: 3, radius: 2, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 2, children: [
1250
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WarningOutlineIcon, { "aria-hidden": "true" }),
1251
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { size: 1, children: [
1157
1252
  "Status updates paused \u2014 ",
1158
1253
  pollError
1159
1254
  ] })
1160
1255
  ] }) })
1161
1256
  ] }),
1162
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box, { children: [
1163
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1257
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box, { children: [
1258
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1164
1259
  Button,
1165
1260
  {
1166
1261
  mode: "ghost",
@@ -1173,61 +1268,61 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1173
1268
  style: { width: "100%", justifyContent: "flex-start", borderRadius: 0, cursor: "pointer" }
1174
1269
  }
1175
1270
  ),
1176
- showDetails && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Card, { tone: "primary", padding: 3, className: "dvfs-accordion-content", style: { borderRadius: 0, borderTop: "1px solid rgba(128,128,128,0.15)" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 2, children: [
1177
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "center", children: [
1178
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Project" }),
1179
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: projectId || "\u2014" })
1271
+ showDetails && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Card, { tone: "primary", padding: 3, className: "dvfs-accordion-content", style: { borderRadius: 0, borderTop: "1px solid rgba(128,128,128,0.15)" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 2, children: [
1272
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "center", children: [
1273
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Project" }),
1274
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: projectId || "\u2014" })
1180
1275
  ] }),
1181
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "center", children: [
1182
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Hook" }),
1183
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: hookId || "\u2014" })
1276
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "center", children: [
1277
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Hook" }),
1278
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: hookId || "\u2014" })
1184
1279
  ] }),
1185
- target.teamId && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "center", children: [
1186
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Team" }),
1187
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: target.teamId })
1280
+ target.teamId && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "center", children: [
1281
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Team" }),
1282
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: target.teamId })
1188
1283
  ] }),
1189
- fullSha && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "flex-start", children: [
1190
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Commit" }),
1191
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: fullSha })
1284
+ fullSha && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "flex-start", children: [
1285
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Commit" }),
1286
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: fullSha })
1192
1287
  ] }),
1193
- latest?.meta?.githubCommitAuthorName && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "center", children: [
1194
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Author" }),
1195
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, children: latest.meta.githubCommitAuthorName })
1288
+ latest?.meta?.githubCommitAuthorName && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "center", children: [
1289
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Author" }),
1290
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, children: latest.meta.githubCommitAuthorName })
1196
1291
  ] }),
1197
- branch && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "center", children: [
1198
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Branch" }),
1199
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: branch })
1292
+ branch && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "center", children: [
1293
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Branch" }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: branch })
1200
1295
  ] }),
1201
- latest?.uid && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "center", children: [
1202
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Deploy ID" }),
1203
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: latest.uid })
1296
+ latest?.uid && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "center", children: [
1297
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Deploy ID" }),
1298
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: latest.uid })
1204
1299
  ] }),
1205
- latest?.url && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "flex-start", children: [
1206
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "URL" }),
1207
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: latest.url })
1300
+ latest?.url && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "flex-start", children: [
1301
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "URL" }),
1302
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace", wordBreak: "break-all" }, children: latest.url })
1208
1303
  ] }),
1209
- safeHref(latest?.inspectorUrl) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "center", children: [
1210
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Inspector" }),
1211
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { align: "center", gap: 1, children: [
1212
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: "Open in Vercel" }),
1213
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LaunchIcon, { style: { width: 10, height: 10 } })
1304
+ safeHref(latest?.inspectorUrl) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "center", children: [
1305
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Inspector" }),
1306
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { href: safeHref(latest?.inspectorUrl), target: "_blank", rel: "noreferrer", style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 1, children: [
1307
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, style: { fontFamily: "monospace" }, children: "Open in Vercel" }),
1308
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LaunchIcon, { style: { width: 10, height: 10 } })
1214
1309
  ] }) })
1215
1310
  ] }),
1216
- latest?.created && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Flex, { gap: 2, align: "center", children: [
1217
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Created" }),
1218
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 0, muted: true, children: new Date(latest.created).toLocaleString() })
1311
+ latest?.created && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, align: "center", children: [
1312
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, weight: "semibold", style: { minWidth: LABEL_WIDTH }, children: "Created" }),
1313
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, children: new Date(latest.created).toLocaleString() })
1219
1314
  ] })
1220
1315
  ] }) })
1221
1316
  ] })
1222
1317
  ] }),
1223
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1318
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1224
1319
  Flex,
1225
1320
  {
1226
1321
  direction: "column",
1227
1322
  gap: 2,
1228
1323
  className: "dvfs-deploy-col",
1229
1324
  style: { flexShrink: 0, alignSelf: "stretch" },
1230
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1325
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1231
1326
  Button,
1232
1327
  {
1233
1328
  text: "Deploy",
@@ -1247,7 +1342,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1247
1342
  }
1248
1343
  )
1249
1344
  ] }) }),
1250
- showHistory && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1345
+ showHistory && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1251
1346
  DeployHistory,
1252
1347
  {
1253
1348
  target,
@@ -1259,19 +1354,19 @@ function DeployItem({ target, token, onDelete, onEdit }) {
1259
1354
  }
1260
1355
 
1261
1356
  // src/components/TokenSetup.tsx
1262
- var import_react8 = require("react");
1263
- var import_sanity = require("sanity");
1264
- var import_jsx_runtime10 = require("react/jsx-runtime");
1357
+ var import_react9 = require("react");
1358
+ var import_sanity2 = require("sanity");
1359
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1265
1360
  var TOKEN_DOC_ID = "config.vercelDeploy";
1266
1361
  function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1267
- const dialogId = (0, import_react8.useId)();
1268
- const tokenId = (0, import_react8.useId)();
1269
- const client = (0, import_sanity.useClient)({ apiVersion: "2025-01-01" });
1270
- const [token, setToken] = (0, import_react8.useState)("");
1271
- const [saving, setSaving] = (0, import_react8.useState)(false);
1272
- const [error, setError] = (0, import_react8.useState)(null);
1273
- const [revoking, setRevoking] = (0, import_react8.useState)(false);
1274
- const save = (0, import_react8.useCallback)(async () => {
1362
+ const dialogId = (0, import_react9.useId)();
1363
+ const tokenId = (0, import_react9.useId)();
1364
+ const client = (0, import_sanity2.useClient)({ apiVersion: "2025-01-01" });
1365
+ const [token, setToken] = (0, import_react9.useState)("");
1366
+ const [saving, setSaving] = (0, import_react9.useState)(false);
1367
+ const [error, setError] = (0, import_react9.useState)(null);
1368
+ const [revoking, setRevoking] = (0, import_react9.useState)(false);
1369
+ const save = (0, import_react9.useCallback)(async () => {
1275
1370
  if (!token.trim()) return;
1276
1371
  setSaving(true);
1277
1372
  setError(null);
@@ -1288,7 +1383,7 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1288
1383
  setSaving(false);
1289
1384
  }
1290
1385
  }, [client, token, onSaved]);
1291
- const revoke = (0, import_react8.useCallback)(async () => {
1386
+ const revoke = (0, import_react9.useCallback)(async () => {
1292
1387
  setRevoking(true);
1293
1388
  setError(null);
1294
1389
  try {
@@ -1300,15 +1395,15 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1300
1395
  setRevoking(false);
1301
1396
  }
1302
1397
  }, [client, onSaved]);
1303
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1398
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1304
1399
  Dialog,
1305
1400
  {
1306
1401
  header: "Connect Vercel API token",
1307
1402
  id: dialogId,
1308
1403
  onClose: onCancel,
1309
1404
  width: 1,
1310
- footer: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { padding: 3, gap: 2, justify: hasToken ? "space-between" : "flex-end", children: [
1311
- hasToken && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1405
+ footer: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Flex, { padding: 3, gap: 2, justify: hasToken ? "space-between" : "flex-end", children: [
1406
+ hasToken && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1312
1407
  Button,
1313
1408
  {
1314
1409
  text: "Remove token",
@@ -1321,9 +1416,9 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1321
1416
  style: { cursor: "pointer" }
1322
1417
  }
1323
1418
  ),
1324
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { gap: 2, children: [
1325
- onCancel && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { text: "Cancel", mode: "ghost", onClick: onCancel, style: { cursor: "pointer" } }),
1326
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1419
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Flex, { gap: 2, children: [
1420
+ onCancel && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { text: "Cancel", mode: "ghost", onClick: onCancel, style: { cursor: "pointer" } }),
1421
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1327
1422
  Button,
1328
1423
  {
1329
1424
  text: "Save and connect",
@@ -1337,21 +1432,22 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1337
1432
  )
1338
1433
  ] })
1339
1434
  ] }),
1340
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 4, padding: 4, children: [
1341
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 3, children: [
1342
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(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." }),
1343
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { size: 1, muted: true, children: [
1435
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Stack, { space: 4, padding: 4, children: [
1436
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Stack, { space: 3, children: [
1437
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(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." }),
1438
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { size: 1, muted: true, children: [
1344
1439
  "Create one at ",
1345
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "vercel.com \u2192 Settings \u2192 Tokens" }),
1440
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: "vercel.com \u2192 Settings \u2192 Tokens" }),
1346
1441
  " with",
1347
1442
  " ",
1348
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "Full Account" }),
1349
- " scope. The token is stored in your Sanity dataset and shared across all authenticated studio users."
1443
+ "scope limited to the ",
1444
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: "team" }),
1445
+ " 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."
1350
1446
  ] })
1351
1447
  ] }),
1352
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Stack, { space: 2, children: [
1353
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Label, { as: "label", size: 1, htmlFor: tokenId, children: "Vercel API Token" }),
1354
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1448
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Stack, { space: 2, children: [
1449
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Label, { as: "label", size: 1, htmlFor: tokenId, children: "Vercel API Token" }),
1450
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1355
1451
  TextInput,
1356
1452
  {
1357
1453
  id: tokenId,
@@ -1362,37 +1458,41 @@ function TokenSetup({ onSaved, onCancel, hasToken = false }) {
1362
1458
  }
1363
1459
  )
1364
1460
  ] }),
1365
- error && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Card, { tone: "critical", padding: 3, radius: 2, role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 1, children: error }) })
1461
+ error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Card, { tone: "critical", padding: 3, radius: 2, role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { size: 1, children: error }) })
1366
1462
  ] })
1367
1463
  }
1368
1464
  );
1369
1465
  }
1370
1466
 
1371
1467
  // src/components/DeployTargetForm.tsx
1372
- var import_react9 = require("react");
1373
- var import_sanity2 = require("sanity");
1374
- var import_jsx_runtime11 = require("react/jsx-runtime");
1468
+ var import_react10 = require("react");
1469
+ var import_sanity3 = require("sanity");
1470
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1375
1471
  var VERCEL_HOOK_RE2 = /^https:\/\/api\.vercel\.com\/v1\/integrations\/deploy\//;
1376
1472
  function DeployTargetForm({ initial, onSaved, onClose }) {
1377
- const client = (0, import_sanity2.useClient)({ apiVersion: "2025-01-01" });
1473
+ const client = (0, import_sanity3.useClient)({ apiVersion: "2025-01-01" });
1378
1474
  const isEdit = Boolean(initial);
1379
- const dialogId = (0, import_react9.useId)();
1380
- const nameId = (0, import_react9.useId)();
1381
- const urlId = (0, import_react9.useId)();
1382
- const urlErrorId = (0, import_react9.useId)();
1383
- const urlHelpId = (0, import_react9.useId)();
1384
- const teamId_ = (0, import_react9.useId)();
1385
- const teamHelpId = (0, import_react9.useId)();
1386
- const disableId = (0, import_react9.useId)();
1387
- const [name, setName] = (0, import_react9.useState)(initial?.name ?? "");
1388
- const [url, setUrl] = (0, import_react9.useState)(initial?.url ?? "");
1389
- const [teamId, setTeamId] = (0, import_react9.useState)(initial?.teamId ?? "");
1390
- const [disableDelete, setDisableDelete] = (0, import_react9.useState)(initial?.disableDeleteAction ?? false);
1391
- const [saving, setSaving] = (0, import_react9.useState)(false);
1392
- const [error, setError] = (0, import_react9.useState)(null);
1475
+ const pluginConfig = usePluginConfig();
1476
+ const proxyKeyId = (0, import_react10.useId)();
1477
+ const dialogId = (0, import_react10.useId)();
1478
+ const nameId = (0, import_react10.useId)();
1479
+ const urlId = (0, import_react10.useId)();
1480
+ const urlErrorId = (0, import_react10.useId)();
1481
+ const urlHelpId = (0, import_react10.useId)();
1482
+ const teamId_ = (0, import_react10.useId)();
1483
+ const teamHelpId = (0, import_react10.useId)();
1484
+ const disableId = (0, import_react10.useId)();
1485
+ const [name, setName] = (0, import_react10.useState)(initial?.name ?? "");
1486
+ const [url, setUrl] = (0, import_react10.useState)(initial?.url ?? "");
1487
+ const [teamId, setTeamId] = (0, import_react10.useState)(initial?.teamId ?? "");
1488
+ const [proxyKey, setProxyKey] = (0, import_react10.useState)(initial?.proxyKey ?? "");
1489
+ const [disableDelete, setDisableDelete] = (0, import_react10.useState)(initial?.disableDeleteAction ?? false);
1490
+ const [saving, setSaving] = (0, import_react10.useState)(false);
1491
+ const [error, setError] = (0, import_react10.useState)(null);
1393
1492
  const urlValid = !url || VERCEL_HOOK_RE2.test(url.trim());
1394
- const canSave = name.trim() && url.trim() && urlValid;
1395
- const save = (0, import_react9.useCallback)(async () => {
1493
+ const isProxy = pluginConfig.mode === "proxy";
1494
+ const canSave = Boolean(name.trim()) && urlValid && (isProxy ? Boolean(proxyKey.trim()) : Boolean(url.trim()));
1495
+ const save = (0, import_react10.useCallback)(async () => {
1396
1496
  if (!canSave) return;
1397
1497
  setSaving(true);
1398
1498
  setError(null);
@@ -1400,6 +1500,7 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1400
1500
  name: name.trim(),
1401
1501
  url: url.trim(),
1402
1502
  teamId: teamId.trim() || null,
1503
+ proxyKey: proxyKey.trim() || null,
1403
1504
  disableDeleteAction: disableDelete
1404
1505
  };
1405
1506
  try {
@@ -1414,17 +1515,17 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1414
1515
  } finally {
1415
1516
  setSaving(false);
1416
1517
  }
1417
- }, [canSave, isEdit, initial, client, name, url, teamId, disableDelete, onSaved]);
1418
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1518
+ }, [canSave, isEdit, initial, client, name, url, teamId, proxyKey, disableDelete, onSaved]);
1519
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1419
1520
  Dialog,
1420
1521
  {
1421
1522
  header: isEdit ? `Edit "${initial?.name}"` : "Add deploy target",
1422
1523
  id: dialogId,
1423
1524
  onClose,
1424
1525
  width: 1,
1425
- footer: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
1426
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { text: "Cancel", mode: "ghost", onClick: onClose, style: { cursor: "pointer" } }),
1427
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1526
+ footer: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
1527
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Button, { text: "Cancel", mode: "ghost", onClick: onClose, style: { cursor: "pointer" } }),
1528
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1428
1529
  Button,
1429
1530
  {
1430
1531
  text: isEdit ? "Save changes" : "Add target",
@@ -1437,13 +1538,13 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1437
1538
  }
1438
1539
  )
1439
1540
  ] }),
1440
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Box, { padding: 4, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Stack, { space: 4, children: [
1441
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Stack, { space: 2, children: [
1442
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Label, { as: "label", size: 1, htmlFor: nameId, children: [
1541
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Box, { padding: 4, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 4, children: [
1542
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 2, children: [
1543
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Label, { as: "label", size: 1, htmlFor: nameId, children: [
1443
1544
  "Name ",
1444
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", children: "*" })
1545
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { "aria-hidden": "true", children: "*" })
1445
1546
  ] }),
1446
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1547
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1447
1548
  TextInput,
1448
1549
  {
1449
1550
  id: nameId,
@@ -1455,12 +1556,29 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1455
1556
  }
1456
1557
  )
1457
1558
  ] }),
1458
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Stack, { space: 2, children: [
1459
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Label, { as: "label", size: 1, htmlFor: urlId, children: [
1559
+ isProxy ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 2, children: [
1560
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Label, { as: "label", size: 1, htmlFor: proxyKeyId, children: [
1561
+ "Proxy Key ",
1562
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { "aria-hidden": "true", children: "*" })
1563
+ ] }),
1564
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1565
+ TextInput,
1566
+ {
1567
+ id: proxyKeyId,
1568
+ required: true,
1569
+ "aria-required": "true",
1570
+ value: proxyKey,
1571
+ onChange: (e) => setProxyKey(e.target.value),
1572
+ placeholder: "production"
1573
+ }
1574
+ ),
1575
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { size: 0, muted: true, children: "Matches a key configured on your deploy proxy, which holds the real hook URL. Contains no secret." })
1576
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 2, children: [
1577
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Label, { as: "label", size: 1, htmlFor: urlId, children: [
1460
1578
  "Deploy hook URL ",
1461
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", children: "*" })
1579
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { "aria-hidden": "true", children: "*" })
1462
1580
  ] }),
1463
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1581
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1464
1582
  TextInput,
1465
1583
  {
1466
1584
  id: urlId,
@@ -1473,15 +1591,15 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1473
1591
  placeholder: "https://api.vercel.com/v1/integrations/deploy/\u2026"
1474
1592
  }
1475
1593
  ),
1476
- url && !urlValid && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Card, { tone: "critical", padding: 2, radius: 2, role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { id: urlErrorId, size: 1, children: "Must be a Vercel deploy hook URL (api.vercel.com/v1/integrations/deploy/\u2026)" }) }),
1477
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { id: urlHelpId, size: 0, muted: true, children: "Vercel dashboard \u2192 Project \u2192 Settings \u2192 Git \u2192 Deploy Hooks" })
1594
+ url && !urlValid && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Card, { tone: "critical", padding: 2, radius: 2, role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { id: urlErrorId, size: 1, children: "Must be a Vercel deploy hook URL (api.vercel.com/v1/integrations/deploy/\u2026)" }) }),
1595
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { id: urlHelpId, size: 0, muted: true, children: "Vercel dashboard \u2192 Project \u2192 Settings \u2192 Git \u2192 Deploy Hooks" })
1478
1596
  ] }),
1479
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Stack, { space: 2, children: [
1480
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Label, { as: "label", size: 1, htmlFor: teamId_, children: [
1597
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 2, children: [
1598
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Label, { as: "label", size: 1, htmlFor: teamId_, children: [
1481
1599
  "Team ID ",
1482
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { opacity: 0.5, fontWeight: "normal" }, children: "\u2014 optional" })
1600
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { opacity: 0.5, fontWeight: "normal" }, children: "\u2014 optional" })
1483
1601
  ] }),
1484
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1602
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1485
1603
  TextInput,
1486
1604
  {
1487
1605
  id: teamId_,
@@ -1491,14 +1609,10 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1491
1609
  placeholder: "team_xxxxxxxx"
1492
1610
  }
1493
1611
  ),
1494
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { id: teamHelpId, size: 0, muted: true, children: [
1495
- "Required for team-owned Vercel projects. Find it at Vercel \u2192 Settings \u2192 General \u2192 Team ID (starts with ",
1496
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { children: "team_" }),
1497
- ")."
1498
- ] })
1612
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(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_)." })
1499
1613
  ] }),
1500
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Flex, { align: "center", gap: 3, children: [
1501
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1614
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Flex, { align: "center", gap: 3, children: [
1615
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1502
1616
  Switch,
1503
1617
  {
1504
1618
  checked: disableDelete,
@@ -1506,36 +1620,38 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
1506
1620
  id: disableId
1507
1621
  }
1508
1622
  ),
1509
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Stack, { space: 1, children: [
1510
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Label, { as: "label", size: 1, htmlFor: disableId, children: "Disable delete action" }),
1511
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { size: 0, muted: true, children: "Hides the delete button for this target in the studio." })
1623
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 1, children: [
1624
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Label, { as: "label", size: 1, htmlFor: disableId, children: "Disable delete action" }),
1625
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { size: 0, muted: true, children: "Hides the delete button for this target in the studio." })
1512
1626
  ] })
1513
1627
  ] }),
1514
- error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Card, { tone: "critical", padding: 3, radius: 2, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { size: 1, children: error }) })
1628
+ error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Card, { tone: "critical", padding: 3, radius: 2, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { size: 1, children: error }) })
1515
1629
  ] }) })
1516
1630
  }
1517
1631
  );
1518
1632
  }
1519
1633
 
1520
1634
  // src/version.ts
1521
- var VERSION = "1.2.1";
1635
+ var VERSION = "1.3.0";
1522
1636
 
1523
1637
  // src/components/DeployTool.tsx
1524
- var import_jsx_runtime12 = require("react/jsx-runtime");
1638
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1525
1639
  var TOKEN_QUERY = `*[_id == "config.vercelDeploy"][0].accessToken`;
1526
1640
  var TARGETS_QUERY = `*[_type == "vercel_deploy" && !(_id in path("drafts.**"))] | order(_createdAt asc)`;
1527
1641
  function DeployTool() {
1528
- const client = (0, import_sanity3.useClient)({ apiVersion: "2025-01-01" });
1642
+ const client = (0, import_sanity4.useClient)({ apiVersion: "2025-01-01" });
1643
+ const pluginConfig = usePluginConfig();
1644
+ const usesToken = pluginConfig.mode === "direct";
1529
1645
  const toast = useToast();
1530
- const [token, setToken] = (0, import_react10.useState)(null);
1531
- const [targets, setTargets] = (0, import_react10.useState)([]);
1532
- const [loading, setLoading] = (0, import_react10.useState)(true);
1533
- const [showTokenSetup, setShowTokenSetup] = (0, import_react10.useState)(false);
1534
- const [showCreateForm, setShowCreateForm] = (0, import_react10.useState)(false);
1535
- const [pendingEdit, setPendingEdit] = (0, import_react10.useState)(null);
1536
- const [pendingDelete, setPendingDelete] = (0, import_react10.useState)(null);
1537
- const [deleting, setDeleting] = (0, import_react10.useState)(false);
1538
- const load = (0, import_react10.useCallback)(async () => {
1646
+ const [token, setToken] = (0, import_react11.useState)(null);
1647
+ const [targets, setTargets] = (0, import_react11.useState)([]);
1648
+ const [loading, setLoading] = (0, import_react11.useState)(true);
1649
+ const [showTokenSetup, setShowTokenSetup] = (0, import_react11.useState)(false);
1650
+ const [showCreateForm, setShowCreateForm] = (0, import_react11.useState)(false);
1651
+ const [pendingEdit, setPendingEdit] = (0, import_react11.useState)(null);
1652
+ const [pendingDelete, setPendingDelete] = (0, import_react11.useState)(null);
1653
+ const [deleting, setDeleting] = (0, import_react11.useState)(false);
1654
+ const load = (0, import_react11.useCallback)(async () => {
1539
1655
  setLoading(true);
1540
1656
  try {
1541
1657
  const [fetchedToken, fetchedTargets] = await Promise.all([
@@ -1550,10 +1666,10 @@ function DeployTool() {
1550
1666
  setLoading(false);
1551
1667
  }
1552
1668
  }, [client]);
1553
- (0, import_react10.useEffect)(() => {
1669
+ (0, import_react11.useEffect)(() => {
1554
1670
  load();
1555
1671
  }, [load]);
1556
- (0, import_react10.useEffect)(() => {
1672
+ (0, import_react11.useEffect)(() => {
1557
1673
  const existing = document.getElementById("dvfs-styles");
1558
1674
  if (existing) {
1559
1675
  const n = Number(existing.dataset.refs ?? "1") + 1;
@@ -1591,7 +1707,7 @@ function DeployTool() {
1591
1707
  if (left <= 0) style.remove();
1592
1708
  };
1593
1709
  }, []);
1594
- (0, import_react10.useEffect)(() => {
1710
+ (0, import_react11.useEffect)(() => {
1595
1711
  const sub = client.listen(TARGETS_QUERY).subscribe(() => {
1596
1712
  client.fetch(TARGETS_QUERY).then(setTargets).catch((err) => {
1597
1713
  console.error("deploy-vercel-from-sanity: subscription refresh error", err);
@@ -1599,7 +1715,7 @@ function DeployTool() {
1599
1715
  });
1600
1716
  return () => sub.unsubscribe();
1601
1717
  }, [client]);
1602
- const confirmDelete = (0, import_react10.useCallback)(async () => {
1718
+ const confirmDelete = (0, import_react11.useCallback)(async () => {
1603
1719
  if (!pendingDelete) return;
1604
1720
  setDeleting(true);
1605
1721
  try {
@@ -1616,14 +1732,14 @@ function DeployTool() {
1616
1732
  }
1617
1733
  }, [client, pendingDelete, toast]);
1618
1734
  if (loading) {
1619
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Card, { height: "fill", tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Flex, { align: "center", justify: "center", height: "fill", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Spinner, { muted: true }) }) });
1735
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Card, { height: "fill", tone: "transparent", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Flex, { align: "center", justify: "center", height: "fill", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Spinner, { muted: true }) }) });
1620
1736
  }
1621
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Card, { height: "fill", tone: "transparent", children: [
1622
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Box, { padding: 5, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 5, children: [
1623
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Flex, { align: "center", justify: "space-between", className: "dvfs-header", children: [
1624
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Heading, { size: 2, children: "Deploy with Vercel" }),
1625
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Flex, { align: "center", gap: 3, className: "dvfs-header-actions", children: [
1626
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Card, { height: "fill", tone: "transparent", children: [
1738
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box, { padding: 5, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Stack, { space: 5, children: [
1739
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Flex, { align: "center", justify: "space-between", className: "dvfs-header", children: [
1740
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Heading, { size: 2, children: "Deploy with Vercel" }),
1741
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Flex, { align: "center", gap: 3, className: "dvfs-header-actions", children: [
1742
+ usesToken && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1627
1743
  Button,
1628
1744
  {
1629
1745
  text: token ? "Token connected" : "Connect API token",
@@ -1635,7 +1751,7 @@ function DeployTool() {
1635
1751
  style: { cursor: "pointer" }
1636
1752
  }
1637
1753
  ),
1638
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1754
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1639
1755
  Button,
1640
1756
  {
1641
1757
  text: "Add target",
@@ -1648,12 +1764,12 @@ function DeployTool() {
1648
1764
  )
1649
1765
  ] })
1650
1766
  ] }),
1651
- !token && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Card, { padding: 4, radius: 2, tone: "caution", shadow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Flex, { align: "center", justify: "space-between", gap: 4, children: [
1652
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 2, children: [
1653
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { size: 1, weight: "semibold", children: "Deploy status is not connected" }),
1654
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(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." })
1767
+ usesToken && !token && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Card, { padding: 4, radius: 2, tone: "caution", shadow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Flex, { align: "center", justify: "space-between", gap: 4, children: [
1768
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Stack, { space: 2, children: [
1769
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { size: 1, weight: "semibold", children: "Deploy status is not connected" }),
1770
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(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." })
1655
1771
  ] }),
1656
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1772
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1657
1773
  Button,
1658
1774
  {
1659
1775
  text: "Connect",
@@ -1664,15 +1780,15 @@ function DeployTool() {
1664
1780
  }
1665
1781
  )
1666
1782
  ] }) }),
1667
- targets.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Card, { padding: 5, radius: 2, tone: "transparent", shadow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 4, style: { textAlign: "center" }, children: [
1668
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { size: 2, weight: "semibold", children: "No deploy targets configured" }),
1669
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { size: 1, muted: true, children: [
1783
+ targets.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Card, { padding: 5, radius: 2, tone: "transparent", shadow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Stack, { space: 4, style: { textAlign: "center" }, children: [
1784
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { size: 2, weight: "semibold", children: "No deploy targets configured" }),
1785
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { size: 1, muted: true, children: [
1670
1786
  "Add a deploy target using the button above, or create a",
1671
1787
  " ",
1672
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("code", { children: "vercel_deploy" }),
1788
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { children: "vercel_deploy" }),
1673
1789
  " document directly in the dataset."
1674
1790
  ] }),
1675
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Flex, { justify: "center", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1791
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Flex, { justify: "center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1676
1792
  Button,
1677
1793
  {
1678
1794
  text: "Add deploy target",
@@ -1683,12 +1799,12 @@ function DeployTool() {
1683
1799
  }
1684
1800
  ) })
1685
1801
  ] }) }),
1686
- targets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "dvfs-grid", style: {
1802
+ targets.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "dvfs-grid", style: {
1687
1803
  display: "grid",
1688
1804
  gridTemplateColumns: "repeat(auto-fill, minmax(min(540px, 100%), 1fr))",
1689
1805
  gap: "16px",
1690
1806
  alignItems: "start"
1691
- }, children: targets.map((target) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1807
+ }, children: targets.map((target) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1692
1808
  DeployItem,
1693
1809
  {
1694
1810
  target,
@@ -1699,7 +1815,7 @@ function DeployTool() {
1699
1815
  target._id
1700
1816
  )) })
1701
1817
  ] }) }),
1702
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1818
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1703
1819
  Box,
1704
1820
  {
1705
1821
  style: {
@@ -1710,13 +1826,13 @@ function DeployTool() {
1710
1826
  pointerEvents: "none",
1711
1827
  userSelect: "none"
1712
1828
  },
1713
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { size: 0, muted: true, children: [
1829
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { size: 0, muted: true, children: [
1714
1830
  "v",
1715
1831
  VERSION
1716
1832
  ] })
1717
1833
  }
1718
1834
  ),
1719
- showTokenSetup && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1835
+ showTokenSetup && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1720
1836
  TokenSetup,
1721
1837
  {
1722
1838
  onSaved: () => {
@@ -1727,7 +1843,7 @@ function DeployTool() {
1727
1843
  hasToken: Boolean(token)
1728
1844
  }
1729
1845
  ),
1730
- showCreateForm && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1846
+ showCreateForm && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1731
1847
  DeployTargetForm,
1732
1848
  {
1733
1849
  onSaved: () => {
@@ -1737,7 +1853,7 @@ function DeployTool() {
1737
1853
  onClose: () => setShowCreateForm(false)
1738
1854
  }
1739
1855
  ),
1740
- pendingEdit && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1856
+ pendingEdit && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1741
1857
  DeployTargetForm,
1742
1858
  {
1743
1859
  initial: pendingEdit,
@@ -1748,15 +1864,15 @@ function DeployTool() {
1748
1864
  onClose: () => setPendingEdit(null)
1749
1865
  }
1750
1866
  ),
1751
- pendingDelete && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1867
+ pendingDelete && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1752
1868
  Dialog,
1753
1869
  {
1754
1870
  header: "Delete deploy target?",
1755
1871
  id: "confirm-delete",
1756
1872
  onClose: () => setPendingDelete(null),
1757
1873
  width: 1,
1758
- footer: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
1759
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1874
+ footer: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Flex, { padding: 3, gap: 2, justify: "flex-end", children: [
1875
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1760
1876
  Button,
1761
1877
  {
1762
1878
  text: "Cancel",
@@ -1765,7 +1881,7 @@ function DeployTool() {
1765
1881
  style: { cursor: "pointer" }
1766
1882
  }
1767
1883
  ),
1768
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1884
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1769
1885
  Button,
1770
1886
  {
1771
1887
  text: "Delete",
@@ -1778,28 +1894,28 @@ function DeployTool() {
1778
1894
  }
1779
1895
  )
1780
1896
  ] }),
1781
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Box, { padding: 4, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Stack, { space: 3, children: [
1782
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Flex, { align: "center", gap: 2, children: [
1783
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(WarningOutlineIcon, {}),
1784
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { size: 2, weight: "semibold", children: pendingDelete.name })
1897
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box, { padding: 4, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Stack, { space: 3, children: [
1898
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Flex, { align: "center", gap: 2, children: [
1899
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WarningOutlineIcon, {}),
1900
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { size: 2, weight: "semibold", children: pendingDelete.name })
1785
1901
  ] }),
1786
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { size: 1, muted: true, children: "This removes the deploy target from the dataset. The Vercel deploy hook itself is not affected." })
1902
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { size: 1, muted: true, children: "This removes the deploy target from the dataset. The Vercel deploy hook itself is not affected." })
1787
1903
  ] }) })
1788
1904
  }
1789
1905
  ),
1790
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ToastViewport, {})
1906
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToastViewport, {})
1791
1907
  ] });
1792
1908
  }
1793
1909
 
1794
1910
  // src/schema/vercelDeploy.ts
1795
- var import_sanity4 = require("sanity");
1911
+ var import_sanity5 = require("sanity");
1796
1912
 
1797
1913
  // src/schema/schemaIcon.tsx
1798
- var import_react11 = require("react");
1799
- var import_jsx_runtime13 = require("react/jsx-runtime");
1800
- var SchemaRocketIcon = (0, import_react11.forwardRef)(
1914
+ var import_react12 = require("react");
1915
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1916
+ var SchemaRocketIcon = (0, import_react12.forwardRef)(
1801
1917
  function SchemaRocketIcon2(props, ref) {
1802
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1918
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1803
1919
  "svg",
1804
1920
  {
1805
1921
  width: "1em",
@@ -1811,7 +1927,7 @@ var SchemaRocketIcon = (0, import_react11.forwardRef)(
1811
1927
  focusable: "false",
1812
1928
  ...props,
1813
1929
  ref,
1814
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1930
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1815
1931
  "path",
1816
1932
  {
1817
1933
  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",
@@ -1826,25 +1942,28 @@ var SchemaRocketIcon = (0, import_react11.forwardRef)(
1826
1942
  );
1827
1943
 
1828
1944
  // src/schema/vercelDeploy.ts
1829
- var vercelDeploySchema = (0, import_sanity4.defineType)({
1945
+ var vercelDeploySchema = (0, import_sanity5.defineType)({
1830
1946
  name: "vercel_deploy",
1831
1947
  title: "Deploy Target",
1832
1948
  type: "document",
1833
1949
  icon: SchemaRocketIcon,
1834
1950
  fields: [
1835
- (0, import_sanity4.defineField)({
1951
+ (0, import_sanity5.defineField)({
1836
1952
  name: "name",
1837
1953
  title: "Name",
1838
1954
  type: "string",
1839
1955
  description: 'Display label shown in the Deploy tool (e.g. "Production", "Staging")',
1840
1956
  validation: (Rule) => Rule.required()
1841
1957
  }),
1842
- (0, import_sanity4.defineField)({
1958
+ (0, import_sanity5.defineField)({
1843
1959
  name: "url",
1844
1960
  title: "Deploy Hook URL",
1845
1961
  type: "url",
1846
- description: "From Vercel \u2192 Project Settings \u2192 Git \u2192 Deploy Hooks",
1847
- validation: (Rule) => Rule.required().uri({ scheme: ["https"] }).custom((url) => {
1962
+ 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.",
1963
+ validation: (Rule) => Rule.uri({ scheme: ["https"] }).custom((url, context) => {
1964
+ const doc = context.document;
1965
+ if (!url && !doc?.proxyKey) return "Set either a Deploy Hook URL or a Proxy Key";
1966
+ if (!url) return true;
1848
1967
  if (typeof url !== "string") return true;
1849
1968
  if (!url.includes("api.vercel.com/v1/integrations/deploy/")) {
1850
1969
  return "Must be a Vercel deploy hook URL (api.vercel.com/v1/integrations/deploy/\u2026)";
@@ -1852,13 +1971,24 @@ var vercelDeploySchema = (0, import_sanity4.defineType)({
1852
1971
  return true;
1853
1972
  })
1854
1973
  }),
1855
- (0, import_sanity4.defineField)({
1974
+ (0, import_sanity5.defineField)({
1975
+ name: "proxyKey",
1976
+ title: "Proxy Key",
1977
+ type: "string",
1978
+ description: "Used in proxy mode. Matches a key configured on the deploy proxy, which holds the real hook URL. Contains no secret.",
1979
+ validation: (Rule) => Rule.custom((key, context) => {
1980
+ const doc = context.document;
1981
+ if (!key && !doc?.url) return "Set either a Deploy Hook URL or a Proxy Key";
1982
+ return true;
1983
+ })
1984
+ }),
1985
+ (0, import_sanity5.defineField)({
1856
1986
  name: "teamId",
1857
1987
  title: "Vercel Team ID",
1858
1988
  type: "string",
1859
1989
  description: "Required for team-owned projects \u2014 find it in Vercel Team Settings"
1860
1990
  }),
1861
- (0, import_sanity4.defineField)({
1991
+ (0, import_sanity5.defineField)({
1862
1992
  name: "disableDeleteAction",
1863
1993
  title: "Prevent deletion",
1864
1994
  type: "boolean",
@@ -1871,9 +2001,11 @@ var vercelDeploySchema = (0, import_sanity4.defineType)({
1871
2001
  }
1872
2002
  });
1873
2003
 
1874
- // src/index.ts
1875
- var vercelDeploy = (0, import_sanity5.definePlugin)((options) => {
2004
+ // src/index.tsx
2005
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2006
+ var vercelDeploy = (0, import_sanity6.definePlugin)((options) => {
1876
2007
  const config = options ?? {};
2008
+ const resolved = resolveConfig(options);
1877
2009
  return {
1878
2010
  name: "deploy-vercel-from-sanity",
1879
2011
  schema: {
@@ -1884,7 +2016,8 @@ var vercelDeploy = (0, import_sanity5.definePlugin)((options) => {
1884
2016
  name: config.name ?? "vercel-deploy",
1885
2017
  title: config.title ?? "Deploy",
1886
2018
  icon: config.icon ?? RocketIcon,
1887
- component: DeployTool
2019
+ // Wrapped so the tool tree can read the resolved config without prop drilling.
2020
+ component: () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ConfigProvider, { value: resolved, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DeployTool, {}) })
1888
2021
  }
1889
2022
  ]
1890
2023
  };