@liiift-studio/deploy-vercel-from-sanity 1.5.0 → 1.6.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/README.md +5 -2
- package/dist/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +42 -17
- package/dist/index.mjs +42 -17
- package/package.json +1 -1
- package/proxy/core.ts +13 -2
- package/proxy/nextjs-app-router/route.ts +1 -1
package/README.md
CHANGED
|
@@ -336,8 +336,11 @@ Requirements for the route:
|
|
|
336
336
|
your site's domain, so every call is cross-origin and the preflight fails
|
|
337
337
|
without an allow-list. Echo one allow-listed origin; do not send `*` to an
|
|
338
338
|
endpoint that takes an `Authorization` header.
|
|
339
|
-
- **Restrict which branches it will bump
|
|
340
|
-
|
|
339
|
+
- **Restrict which branches it will bump**, and read that list from the
|
|
340
|
+
environment rather than hard-coding it. The recovery flow only ever needs the
|
|
341
|
+
branches you deploy, but the list has to change when you add a deploy target —
|
|
342
|
+
and a hard-coded list can only be changed by shipping a deploy, which is the
|
|
343
|
+
very thing that is broken when this route is needed.
|
|
341
344
|
- **Answer `{ error }` on failure.** The plugin shows that string to the editor
|
|
342
345
|
verbatim, in preference to its own generic message.
|
|
343
346
|
- **Serve it over https.** The plugin refuses a plaintext endpoint, because the
|
package/dist/index.d.mts
CHANGED
|
@@ -60,6 +60,12 @@ interface VercelDeployment {
|
|
|
60
60
|
* deployment comes back BLOCKED.
|
|
61
61
|
*/
|
|
62
62
|
githubCommitAuthorLogin?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Branch the deploy hook is configured for. Present only on hook-triggered
|
|
65
|
+
* deployments, and more reliable than githubCommitRef for learning which branch
|
|
66
|
+
* a target follows, since it describes the hook rather than one commit.
|
|
67
|
+
*/
|
|
68
|
+
deployHookRef?: string;
|
|
63
69
|
/** GitHub repo in "org/repo" format — used to construct commit links */
|
|
64
70
|
githubRepo?: string;
|
|
65
71
|
/** GitHub org slug — fallback when githubRepo is absent */
|
package/dist/index.d.ts
CHANGED
|
@@ -60,6 +60,12 @@ interface VercelDeployment {
|
|
|
60
60
|
* deployment comes back BLOCKED.
|
|
61
61
|
*/
|
|
62
62
|
githubCommitAuthorLogin?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Branch the deploy hook is configured for. Present only on hook-triggered
|
|
65
|
+
* deployments, and more reliable than githubCommitRef for learning which branch
|
|
66
|
+
* a target follows, since it describes the hook rather than one commit.
|
|
67
|
+
*/
|
|
68
|
+
deployHookRef?: string;
|
|
63
69
|
/** GitHub repo in "org/repo" format — used to construct commit links */
|
|
64
70
|
githubRepo?: string;
|
|
65
71
|
/** GitHub org slug — fallback when githubRepo is absent */
|
package/dist/index.js
CHANGED
|
@@ -617,7 +617,7 @@ async function vercelFetch(path, token, init) {
|
|
|
617
617
|
async function listDeployments(opts) {
|
|
618
618
|
const params = new URLSearchParams({
|
|
619
619
|
projectId: opts.projectId,
|
|
620
|
-
"meta-deployHookId": opts.hookId,
|
|
620
|
+
...opts.branch ? { "meta-githubCommitRef": opts.branch } : { "meta-deployHookId": opts.hookId },
|
|
621
621
|
limit: String(opts.limit ?? 10)
|
|
622
622
|
});
|
|
623
623
|
if (opts.teamId) params.set("teamId", opts.teamId);
|
|
@@ -671,7 +671,7 @@ async function proxyFetch(url, statusKey, init) {
|
|
|
671
671
|
}
|
|
672
672
|
return res.json();
|
|
673
673
|
}
|
|
674
|
-
async function fetchDeployments(transport, target, limit) {
|
|
674
|
+
async function fetchDeployments(transport, target, limit, branch) {
|
|
675
675
|
if (transport.mode === "direct") {
|
|
676
676
|
if (!target.projectId || !target.hookId) return [];
|
|
677
677
|
return listDeployments({
|
|
@@ -679,11 +679,13 @@ async function fetchDeployments(transport, target, limit) {
|
|
|
679
679
|
hookId: target.hookId,
|
|
680
680
|
token: transport.token,
|
|
681
681
|
teamId: target.teamId,
|
|
682
|
-
limit
|
|
682
|
+
limit,
|
|
683
|
+
branch
|
|
683
684
|
});
|
|
684
685
|
}
|
|
685
686
|
const params = new URLSearchParams({ key: target.proxyKey ?? "" });
|
|
686
687
|
if (limit) params.set("limit", String(limit));
|
|
688
|
+
if (branch) params.set("branch", branch);
|
|
687
689
|
const data = await proxyFetch(
|
|
688
690
|
`${transport.proxyUrl}/deployments?${params}`,
|
|
689
691
|
transport.statusKey
|
|
@@ -952,7 +954,7 @@ function StatusBadge({ state, showSpinner }) {
|
|
|
952
954
|
// src/components/DeployHistory.tsx
|
|
953
955
|
var import_react7 = require("react");
|
|
954
956
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
955
|
-
function DeployHistory({ target, token, onClose }) {
|
|
957
|
+
function DeployHistory({ target, token, branch, onClose }) {
|
|
956
958
|
const dialogId = (0, import_react7.useId)();
|
|
957
959
|
const pluginConfig = usePluginConfig();
|
|
958
960
|
const [deployments, setDeployments] = (0, import_react7.useState)([]);
|
|
@@ -971,14 +973,14 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
971
973
|
setLoading(true);
|
|
972
974
|
setError(null);
|
|
973
975
|
try {
|
|
974
|
-
const data = await fetchDeployments(transport, targetRef, 20);
|
|
976
|
+
const data = await fetchDeployments(transport, targetRef, 20, branch);
|
|
975
977
|
setDeployments(data);
|
|
976
978
|
} catch (err) {
|
|
977
979
|
setError(err instanceof Error ? err.message : "Failed to load history");
|
|
978
980
|
} finally {
|
|
979
981
|
setLoading(false);
|
|
980
982
|
}
|
|
981
|
-
}, [transport, targetRef]);
|
|
983
|
+
}, [transport, targetRef, branch]);
|
|
982
984
|
(0, import_react7.useEffect)(() => {
|
|
983
985
|
load();
|
|
984
986
|
}, [load]);
|
|
@@ -1004,7 +1006,7 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
1004
1006
|
] }) }),
|
|
1005
1007
|
deployments.map((d) => {
|
|
1006
1008
|
const { label, tone } = stateLabel(d.state);
|
|
1007
|
-
const
|
|
1009
|
+
const branch2 = d.meta?.githubCommitRef ?? "\u2014";
|
|
1008
1010
|
const sha = shortSha(d.meta?.githubCommitSha);
|
|
1009
1011
|
const message = d.meta?.githubCommitMessage?.split("\n")[0] ?? "";
|
|
1010
1012
|
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: [
|
|
@@ -1020,7 +1022,7 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
1020
1022
|
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, muted: true, children: "\u2014" }) }),
|
|
1021
1023
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Badge, { tone, children: label }) }),
|
|
1022
1024
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { flex: 2, style: { overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Stack, { space: 1, children: [
|
|
1023
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children:
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { size: 1, children: branch2 }),
|
|
1024
1026
|
sha && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { size: 0, muted: true, children: [
|
|
1025
1027
|
sha,
|
|
1026
1028
|
message ? ` \xB7 ${message.slice(0, 40)}${message.length > 40 ? "\u2026" : ""}` : ""
|
|
@@ -1054,6 +1056,7 @@ var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
|
1054
1056
|
var POLL_INTERVAL_MS = 5e3;
|
|
1055
1057
|
var LABEL_WIDTH = 64;
|
|
1056
1058
|
var PENDING_TIMEOUT_MS = 6e4;
|
|
1059
|
+
var BUMP_WATCH_TIMEOUT_MS = 3e5;
|
|
1057
1060
|
function DeployItem({ target, token, onDelete, onEdit }) {
|
|
1058
1061
|
const { projectId, hookId } = parseHookUrl(target.url);
|
|
1059
1062
|
const toast = useToast();
|
|
@@ -1083,8 +1086,11 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1083
1086
|
const [logError, setLogError] = (0, import_react8.useState)(null);
|
|
1084
1087
|
const [pollError, setPollError] = (0, import_react8.useState)(null);
|
|
1085
1088
|
const [bumping, setBumping] = (0, import_react8.useState)(false);
|
|
1089
|
+
const [awaitingBump, setAwaitingBump] = (0, import_react8.useState)(false);
|
|
1090
|
+
const [knownBranch, setKnownBranch] = (0, import_react8.useState)(void 0);
|
|
1086
1091
|
const [bumpResult, setBumpResult] = (0, import_react8.useState)(null);
|
|
1087
1092
|
const triggeredFromUidRef = (0, import_react8.useRef)(void 0);
|
|
1093
|
+
const bumpedFromUidRef = (0, import_react8.useRef)(void 0);
|
|
1088
1094
|
const requestSeqRef = (0, import_react8.useRef)(0);
|
|
1089
1095
|
const mountedRef = (0, import_react8.useRef)(true);
|
|
1090
1096
|
(0, import_react8.useEffect)(() => {
|
|
@@ -1101,24 +1107,37 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1101
1107
|
if (!ready) return;
|
|
1102
1108
|
const seq = ++requestSeqRef.current;
|
|
1103
1109
|
try {
|
|
1104
|
-
const data = await fetchDeployments(transport, targetRef);
|
|
1110
|
+
const data = await fetchDeployments(transport, targetRef, void 0, knownBranch);
|
|
1105
1111
|
if (seq !== requestSeqRef.current || !mountedRef.current) return;
|
|
1106
1112
|
setDeployments(data);
|
|
1107
1113
|
setPollError(null);
|
|
1114
|
+
if (!knownBranch) {
|
|
1115
|
+
const learned = data[0]?.meta?.deployHookRef ?? data[0]?.meta?.githubCommitRef;
|
|
1116
|
+
if (learned) setKnownBranch(learned);
|
|
1117
|
+
}
|
|
1108
1118
|
} catch (err) {
|
|
1109
1119
|
if (seq !== requestSeqRef.current || !mountedRef.current) return;
|
|
1110
1120
|
setPollError(err instanceof Error ? err.message : "Could not reach the Vercel API");
|
|
1111
1121
|
console.error("Deploy-vercel-from-sanity: fetch error", err);
|
|
1112
1122
|
}
|
|
1113
|
-
}, [transport, targetRef]);
|
|
1123
|
+
}, [transport, targetRef, knownBranch]);
|
|
1114
1124
|
(0, import_react8.useEffect)(() => {
|
|
1115
1125
|
fetchDeployments2().finally(() => setLoadingInitial(false));
|
|
1116
1126
|
}, [fetchDeployments2]);
|
|
1117
1127
|
(0, import_react8.useEffect)(() => {
|
|
1118
|
-
if (!isActive) return;
|
|
1128
|
+
if (!isActive && !awaitingBump) return;
|
|
1119
1129
|
const id = setInterval(fetchDeployments2, POLL_INTERVAL_MS);
|
|
1120
1130
|
return () => clearInterval(id);
|
|
1121
|
-
}, [isActive, fetchDeployments2]);
|
|
1131
|
+
}, [isActive, awaitingBump, fetchDeployments2]);
|
|
1132
|
+
(0, import_react8.useEffect)(() => {
|
|
1133
|
+
if (!awaitingBump) return;
|
|
1134
|
+
if (latest?.uid && latest.uid !== bumpedFromUidRef.current) setAwaitingBump(false);
|
|
1135
|
+
}, [awaitingBump, latest?.uid]);
|
|
1136
|
+
(0, import_react8.useEffect)(() => {
|
|
1137
|
+
if (!awaitingBump) return;
|
|
1138
|
+
const id = setTimeout(() => setAwaitingBump(false), BUMP_WATCH_TIMEOUT_MS);
|
|
1139
|
+
return () => clearTimeout(id);
|
|
1140
|
+
}, [awaitingBump]);
|
|
1122
1141
|
(0, import_react8.useEffect)(() => {
|
|
1123
1142
|
if (!isPending) return;
|
|
1124
1143
|
if (latest?.uid && latest.uid !== triggeredFromUidRef.current) setPendingSince(null);
|
|
@@ -1248,6 +1267,8 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1248
1267
|
// failure. Unused by workflow-dispatch mode.
|
|
1249
1268
|
studioToken: client.config().token
|
|
1250
1269
|
});
|
|
1270
|
+
bumpedFromUidRef.current = latest?.uid;
|
|
1271
|
+
setAwaitingBump(true);
|
|
1251
1272
|
setBumpResult({
|
|
1252
1273
|
ok: true,
|
|
1253
1274
|
message: `Version bump requested on ${ref}. The new deploy appears here in a minute or two.`
|
|
@@ -1264,7 +1285,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1264
1285
|
} finally {
|
|
1265
1286
|
setBumping(false);
|
|
1266
1287
|
}
|
|
1267
|
-
}, [pluginConfig.unblock, latest?.meta?.githubCommitRef, currentUser, target.name, toast, client]);
|
|
1288
|
+
}, [pluginConfig.unblock, latest?.meta?.githubCommitRef, latest?.uid, currentUser, target.name, toast, client]);
|
|
1268
1289
|
const branch = latest?.meta?.githubCommitRef;
|
|
1269
1290
|
const commitMsg = latest?.meta?.githubCommitMessage?.split("\n")[0];
|
|
1270
1291
|
const sha = shortSha(latest?.meta?.githubCommitSha);
|
|
@@ -1478,9 +1499,12 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1478
1499
|
", which Vercel will build."
|
|
1479
1500
|
] })
|
|
1480
1501
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { size: 0, muted: true, children: pluginConfig.unblock ? "This deployment carries no branch information, so a version bump cannot be targeted. Ask a developer to deploy manually." : "Ask a developer to push a version bump \u2014 a commit by an authorised author is needed before this site can deploy." }),
|
|
1481
|
-
bumpResult && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1482
|
-
|
|
1483
|
-
bumpResult.
|
|
1502
|
+
bumpResult && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Flex, { align: "center", gap: 2, children: [
|
|
1503
|
+
awaitingBump && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner, { muted: true }),
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { size: 0, weight: bumpResult.ok ? "semibold" : void 0, children: [
|
|
1505
|
+
bumpResult.ok && !awaitingBump ? "\u2713 " : "",
|
|
1506
|
+
bumpResult.message
|
|
1507
|
+
] })
|
|
1484
1508
|
] })
|
|
1485
1509
|
] }) })
|
|
1486
1510
|
] }),
|
|
@@ -1585,6 +1609,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1585
1609
|
{
|
|
1586
1610
|
target,
|
|
1587
1611
|
token,
|
|
1612
|
+
branch: knownBranch,
|
|
1588
1613
|
onClose: () => setShowHistory(false)
|
|
1589
1614
|
}
|
|
1590
1615
|
)
|
|
@@ -1870,7 +1895,7 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1870
1895
|
}
|
|
1871
1896
|
|
|
1872
1897
|
// src/version.ts
|
|
1873
|
-
var VERSION = "1.
|
|
1898
|
+
var VERSION = "1.6.0";
|
|
1874
1899
|
|
|
1875
1900
|
// src/components/DeployTool.tsx
|
|
1876
1901
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
package/dist/index.mjs
CHANGED
|
@@ -582,7 +582,7 @@ async function vercelFetch(path, token, init) {
|
|
|
582
582
|
async function listDeployments(opts) {
|
|
583
583
|
const params = new URLSearchParams({
|
|
584
584
|
projectId: opts.projectId,
|
|
585
|
-
"meta-deployHookId": opts.hookId,
|
|
585
|
+
...opts.branch ? { "meta-githubCommitRef": opts.branch } : { "meta-deployHookId": opts.hookId },
|
|
586
586
|
limit: String(opts.limit ?? 10)
|
|
587
587
|
});
|
|
588
588
|
if (opts.teamId) params.set("teamId", opts.teamId);
|
|
@@ -636,7 +636,7 @@ async function proxyFetch(url, statusKey, init) {
|
|
|
636
636
|
}
|
|
637
637
|
return res.json();
|
|
638
638
|
}
|
|
639
|
-
async function fetchDeployments(transport, target, limit) {
|
|
639
|
+
async function fetchDeployments(transport, target, limit, branch) {
|
|
640
640
|
if (transport.mode === "direct") {
|
|
641
641
|
if (!target.projectId || !target.hookId) return [];
|
|
642
642
|
return listDeployments({
|
|
@@ -644,11 +644,13 @@ async function fetchDeployments(transport, target, limit) {
|
|
|
644
644
|
hookId: target.hookId,
|
|
645
645
|
token: transport.token,
|
|
646
646
|
teamId: target.teamId,
|
|
647
|
-
limit
|
|
647
|
+
limit,
|
|
648
|
+
branch
|
|
648
649
|
});
|
|
649
650
|
}
|
|
650
651
|
const params = new URLSearchParams({ key: target.proxyKey ?? "" });
|
|
651
652
|
if (limit) params.set("limit", String(limit));
|
|
653
|
+
if (branch) params.set("branch", branch);
|
|
652
654
|
const data = await proxyFetch(
|
|
653
655
|
`${transport.proxyUrl}/deployments?${params}`,
|
|
654
656
|
transport.statusKey
|
|
@@ -917,7 +919,7 @@ function StatusBadge({ state, showSpinner }) {
|
|
|
917
919
|
// src/components/DeployHistory.tsx
|
|
918
920
|
import { useId as useId3, useEffect as useEffect3, useMemo, useState as useState4, useCallback as useCallback3 } from "react";
|
|
919
921
|
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
920
|
-
function DeployHistory({ target, token, onClose }) {
|
|
922
|
+
function DeployHistory({ target, token, branch, onClose }) {
|
|
921
923
|
const dialogId = useId3();
|
|
922
924
|
const pluginConfig = usePluginConfig();
|
|
923
925
|
const [deployments, setDeployments] = useState4([]);
|
|
@@ -936,14 +938,14 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
936
938
|
setLoading(true);
|
|
937
939
|
setError(null);
|
|
938
940
|
try {
|
|
939
|
-
const data = await fetchDeployments(transport, targetRef, 20);
|
|
941
|
+
const data = await fetchDeployments(transport, targetRef, 20, branch);
|
|
940
942
|
setDeployments(data);
|
|
941
943
|
} catch (err) {
|
|
942
944
|
setError(err instanceof Error ? err.message : "Failed to load history");
|
|
943
945
|
} finally {
|
|
944
946
|
setLoading(false);
|
|
945
947
|
}
|
|
946
|
-
}, [transport, targetRef]);
|
|
948
|
+
}, [transport, targetRef, branch]);
|
|
947
949
|
useEffect3(() => {
|
|
948
950
|
load();
|
|
949
951
|
}, [load]);
|
|
@@ -969,7 +971,7 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
969
971
|
] }) }),
|
|
970
972
|
deployments.map((d) => {
|
|
971
973
|
const { label, tone } = stateLabel(d.state);
|
|
972
|
-
const
|
|
974
|
+
const branch2 = d.meta?.githubCommitRef ?? "\u2014";
|
|
973
975
|
const sha = shortSha(d.meta?.githubCommitSha);
|
|
974
976
|
const message = d.meta?.githubCommitMessage?.split("\n")[0] ?? "";
|
|
975
977
|
return /* @__PURE__ */ jsx9(Card, { padding: 3, radius: 2, shadow: 1, tone: "default", children: /* @__PURE__ */ jsxs5(Flex, { gap: 3, align: "center", children: [
|
|
@@ -985,7 +987,7 @@ function DeployHistory({ target, token, onClose }) {
|
|
|
985
987
|
) : /* @__PURE__ */ jsx9(Text, { size: 1, muted: true, children: "\u2014" }) }),
|
|
986
988
|
/* @__PURE__ */ jsx9(Box, { flex: 1, children: /* @__PURE__ */ jsx9(Badge, { tone, children: label }) }),
|
|
987
989
|
/* @__PURE__ */ jsx9(Box, { flex: 2, style: { overflow: "hidden" }, children: /* @__PURE__ */ jsxs5(Stack, { space: 1, children: [
|
|
988
|
-
/* @__PURE__ */ jsx9(Text, { size: 1, children:
|
|
990
|
+
/* @__PURE__ */ jsx9(Text, { size: 1, children: branch2 }),
|
|
989
991
|
sha && /* @__PURE__ */ jsxs5(Text, { size: 0, muted: true, children: [
|
|
990
992
|
sha,
|
|
991
993
|
message ? ` \xB7 ${message.slice(0, 40)}${message.length > 40 ? "\u2026" : ""}` : ""
|
|
@@ -1019,6 +1021,7 @@ import { Fragment, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
|
1019
1021
|
var POLL_INTERVAL_MS = 5e3;
|
|
1020
1022
|
var LABEL_WIDTH = 64;
|
|
1021
1023
|
var PENDING_TIMEOUT_MS = 6e4;
|
|
1024
|
+
var BUMP_WATCH_TIMEOUT_MS = 3e5;
|
|
1022
1025
|
function DeployItem({ target, token, onDelete, onEdit }) {
|
|
1023
1026
|
const { projectId, hookId } = parseHookUrl(target.url);
|
|
1024
1027
|
const toast = useToast();
|
|
@@ -1048,8 +1051,11 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1048
1051
|
const [logError, setLogError] = useState5(null);
|
|
1049
1052
|
const [pollError, setPollError] = useState5(null);
|
|
1050
1053
|
const [bumping, setBumping] = useState5(false);
|
|
1054
|
+
const [awaitingBump, setAwaitingBump] = useState5(false);
|
|
1055
|
+
const [knownBranch, setKnownBranch] = useState5(void 0);
|
|
1051
1056
|
const [bumpResult, setBumpResult] = useState5(null);
|
|
1052
1057
|
const triggeredFromUidRef = useRef2(void 0);
|
|
1058
|
+
const bumpedFromUidRef = useRef2(void 0);
|
|
1053
1059
|
const requestSeqRef = useRef2(0);
|
|
1054
1060
|
const mountedRef = useRef2(true);
|
|
1055
1061
|
useEffect4(() => {
|
|
@@ -1066,24 +1072,37 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1066
1072
|
if (!ready) return;
|
|
1067
1073
|
const seq = ++requestSeqRef.current;
|
|
1068
1074
|
try {
|
|
1069
|
-
const data = await fetchDeployments(transport, targetRef);
|
|
1075
|
+
const data = await fetchDeployments(transport, targetRef, void 0, knownBranch);
|
|
1070
1076
|
if (seq !== requestSeqRef.current || !mountedRef.current) return;
|
|
1071
1077
|
setDeployments(data);
|
|
1072
1078
|
setPollError(null);
|
|
1079
|
+
if (!knownBranch) {
|
|
1080
|
+
const learned = data[0]?.meta?.deployHookRef ?? data[0]?.meta?.githubCommitRef;
|
|
1081
|
+
if (learned) setKnownBranch(learned);
|
|
1082
|
+
}
|
|
1073
1083
|
} catch (err) {
|
|
1074
1084
|
if (seq !== requestSeqRef.current || !mountedRef.current) return;
|
|
1075
1085
|
setPollError(err instanceof Error ? err.message : "Could not reach the Vercel API");
|
|
1076
1086
|
console.error("Deploy-vercel-from-sanity: fetch error", err);
|
|
1077
1087
|
}
|
|
1078
|
-
}, [transport, targetRef]);
|
|
1088
|
+
}, [transport, targetRef, knownBranch]);
|
|
1079
1089
|
useEffect4(() => {
|
|
1080
1090
|
fetchDeployments2().finally(() => setLoadingInitial(false));
|
|
1081
1091
|
}, [fetchDeployments2]);
|
|
1082
1092
|
useEffect4(() => {
|
|
1083
|
-
if (!isActive) return;
|
|
1093
|
+
if (!isActive && !awaitingBump) return;
|
|
1084
1094
|
const id = setInterval(fetchDeployments2, POLL_INTERVAL_MS);
|
|
1085
1095
|
return () => clearInterval(id);
|
|
1086
|
-
}, [isActive, fetchDeployments2]);
|
|
1096
|
+
}, [isActive, awaitingBump, fetchDeployments2]);
|
|
1097
|
+
useEffect4(() => {
|
|
1098
|
+
if (!awaitingBump) return;
|
|
1099
|
+
if (latest?.uid && latest.uid !== bumpedFromUidRef.current) setAwaitingBump(false);
|
|
1100
|
+
}, [awaitingBump, latest?.uid]);
|
|
1101
|
+
useEffect4(() => {
|
|
1102
|
+
if (!awaitingBump) return;
|
|
1103
|
+
const id = setTimeout(() => setAwaitingBump(false), BUMP_WATCH_TIMEOUT_MS);
|
|
1104
|
+
return () => clearTimeout(id);
|
|
1105
|
+
}, [awaitingBump]);
|
|
1087
1106
|
useEffect4(() => {
|
|
1088
1107
|
if (!isPending) return;
|
|
1089
1108
|
if (latest?.uid && latest.uid !== triggeredFromUidRef.current) setPendingSince(null);
|
|
@@ -1213,6 +1232,8 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1213
1232
|
// failure. Unused by workflow-dispatch mode.
|
|
1214
1233
|
studioToken: client.config().token
|
|
1215
1234
|
});
|
|
1235
|
+
bumpedFromUidRef.current = latest?.uid;
|
|
1236
|
+
setAwaitingBump(true);
|
|
1216
1237
|
setBumpResult({
|
|
1217
1238
|
ok: true,
|
|
1218
1239
|
message: `Version bump requested on ${ref}. The new deploy appears here in a minute or two.`
|
|
@@ -1229,7 +1250,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1229
1250
|
} finally {
|
|
1230
1251
|
setBumping(false);
|
|
1231
1252
|
}
|
|
1232
|
-
}, [pluginConfig.unblock, latest?.meta?.githubCommitRef, currentUser, target.name, toast, client]);
|
|
1253
|
+
}, [pluginConfig.unblock, latest?.meta?.githubCommitRef, latest?.uid, currentUser, target.name, toast, client]);
|
|
1233
1254
|
const branch = latest?.meta?.githubCommitRef;
|
|
1234
1255
|
const commitMsg = latest?.meta?.githubCommitMessage?.split("\n")[0];
|
|
1235
1256
|
const sha = shortSha(latest?.meta?.githubCommitSha);
|
|
@@ -1443,9 +1464,12 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1443
1464
|
", which Vercel will build."
|
|
1444
1465
|
] })
|
|
1445
1466
|
] }) : /* @__PURE__ */ jsx10(Text, { size: 0, muted: true, children: pluginConfig.unblock ? "This deployment carries no branch information, so a version bump cannot be targeted. Ask a developer to deploy manually." : "Ask a developer to push a version bump \u2014 a commit by an authorised author is needed before this site can deploy." }),
|
|
1446
|
-
bumpResult && /* @__PURE__ */ jsxs6(
|
|
1447
|
-
|
|
1448
|
-
bumpResult.
|
|
1467
|
+
bumpResult && /* @__PURE__ */ jsxs6(Flex, { align: "center", gap: 2, children: [
|
|
1468
|
+
awaitingBump && /* @__PURE__ */ jsx10(Spinner, { muted: true }),
|
|
1469
|
+
/* @__PURE__ */ jsxs6(Text, { size: 0, weight: bumpResult.ok ? "semibold" : void 0, children: [
|
|
1470
|
+
bumpResult.ok && !awaitingBump ? "\u2713 " : "",
|
|
1471
|
+
bumpResult.message
|
|
1472
|
+
] })
|
|
1449
1473
|
] })
|
|
1450
1474
|
] }) })
|
|
1451
1475
|
] }),
|
|
@@ -1550,6 +1574,7 @@ function DeployItem({ target, token, onDelete, onEdit }) {
|
|
|
1550
1574
|
{
|
|
1551
1575
|
target,
|
|
1552
1576
|
token,
|
|
1577
|
+
branch: knownBranch,
|
|
1553
1578
|
onClose: () => setShowHistory(false)
|
|
1554
1579
|
}
|
|
1555
1580
|
)
|
|
@@ -1835,7 +1860,7 @@ function DeployTargetForm({ initial, onSaved, onClose }) {
|
|
|
1835
1860
|
}
|
|
1836
1861
|
|
|
1837
1862
|
// src/version.ts
|
|
1838
|
-
var VERSION = "1.
|
|
1863
|
+
var VERSION = "1.6.0";
|
|
1839
1864
|
|
|
1840
1865
|
// src/components/DeployTool.tsx
|
|
1841
1866
|
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liiift-studio/deploy-vercel-from-sanity",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Sanity Studio plugin — trigger and monitor Vercel deployments with full status, history, and build logs. Supports Studio v3.30 through v6.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Liiift Studio",
|
package/proxy/core.ts
CHANGED
|
@@ -184,7 +184,7 @@ async function assertDeploymentInProject(
|
|
|
184
184
|
|
|
185
185
|
/** List recent deployments for a proxy key. */
|
|
186
186
|
export async function handleDeployments(
|
|
187
|
-
params: { key: string | null; limit?: number; statusKey: string | null },
|
|
187
|
+
params: { key: string | null; limit?: number; statusKey: string | null; branch?: string | null },
|
|
188
188
|
env: ProxyEnv,
|
|
189
189
|
): Promise<ProxyResult> {
|
|
190
190
|
const denied = checkStatusKey(params.statusKey, env)
|
|
@@ -192,9 +192,20 @@ export async function handleDeployments(
|
|
|
192
192
|
const project = params.key ? env.projects[params.key.trim().toLowerCase()] : undefined
|
|
193
193
|
if (!project) return { status: 404, body: { error: 'Unknown target key' } }
|
|
194
194
|
|
|
195
|
+
// Branch names come from the caller, so they are held to git's own character set
|
|
196
|
+
// before being spliced into an authenticated query. Anything else is ignored
|
|
197
|
+
// rather than rejected, which degrades to the previous hook-only behaviour.
|
|
198
|
+
const branch = params.branch && /^[A-Za-z0-9._\-/]{1,255}$/.test(params.branch)
|
|
199
|
+
? params.branch
|
|
200
|
+
: undefined
|
|
201
|
+
|
|
195
202
|
const query = new URLSearchParams({
|
|
196
203
|
projectId: project.projectId,
|
|
197
|
-
|
|
204
|
+
// Branch filtering reports what is actually live on that branch; hook filtering
|
|
205
|
+
// only ever shows deployments this tool triggered, so a git push never appears.
|
|
206
|
+
...(branch
|
|
207
|
+
? { 'meta-githubCommitRef': branch }
|
|
208
|
+
: { 'meta-deployHookId': project.hookId }),
|
|
198
209
|
limit: String(params.limit ?? 10),
|
|
199
210
|
})
|
|
200
211
|
if (project.teamId) query.set('teamId', project.teamId)
|
|
@@ -87,7 +87,7 @@ async function handleGet(request: Request): Promise<Response> {
|
|
|
87
87
|
switch (operation(request)) {
|
|
88
88
|
case 'deployments': {
|
|
89
89
|
const limit = Number(url.searchParams.get('limit')) || undefined
|
|
90
|
-
return json(await handleDeployments({ key, limit, statusKey }, env), request)
|
|
90
|
+
return json(await handleDeployments({ key, limit, statusKey, branch: url.searchParams.get('branch') }, env), request)
|
|
91
91
|
}
|
|
92
92
|
case 'events':
|
|
93
93
|
return json(await handleEvents({ key, deploymentId: url.searchParams.get('deploymentId'), statusKey }, env), request)
|