openclaw/scripts/lib/clawhub-publication-state.mjs
Peter Steinberger cfd219c519
fix(release): skip pending ClawHub publications and surface recovery for failed ones (#161985)
The ClawHub release planner and prepared-artifact resolver read the new public publication-state endpoint (/api/v1/packages/{name}/versions/{version}/publication). Only absent versions are republished; pending ones are skipped, and failed ones are excluded, with the recover command printed to the step summary. A 404, or a 200 without a state field, falls back to the legacy version probe.
2026-09-30 09:35:54 -07:00

47 lines
1.6 KiB
JavaScript

export function isClawHubPublishAttemptId(value) {
return typeof value === "string" && /^[A-Za-z0-9_-]{1,200}$/u.test(value);
}
// A legacy router returns version JSON here. Only a missing state permits fallback;
// a new server's unknown or malformed state must never authorize another publish.
export function classifyClawHubPublication(body, { name, version }) {
if (!body || typeof body !== "object" || Array.isArray(body)) {
throw new Error(`Invalid ClawHub publication state for ${name}@${version}.`);
}
if (!Object.hasOwn(body, "state")) {
return null;
}
const { state, stage, attemptId, recoverable, ...identity } = body;
let fields;
switch (state) {
case "published":
case "absent":
fields = [];
break;
case "pending":
fields = ["stage", "attemptId"];
if (
!["staging", "checks", "finalization"].includes(stage) ||
(stage === "staging"
? Object.hasOwn(body, "attemptId")
: !isClawHubPublishAttemptId(attemptId))
) {
fields = null;
}
break;
case "failed":
fields = typeof recoverable === "boolean" ? ["recoverable", "attemptId"] : null;
break;
}
if (
!fields ||
identity.name !== name ||
identity.version !== version ||
Object.keys(body).some((key) => !["name", "version", "state", ...fields].includes(key)) ||
(Object.hasOwn(body, "attemptId") && !isClawHubPublishAttemptId(attemptId))
) {
throw new Error(`Invalid ClawHub publication state for ${name}@${version}.`);
}
const { name: _name, version: _version, ...publication } = body;
return publication;
}