everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
109 lines (107 loc) • 3.61 kB
JavaScript
import { BosConfigSchema } from "../../types.mjs";
import { fetchBosConfigFromFastKv, fetchConfigHistory } from "../registry/fastkv.mjs";
import { buildRollbackPayload, verifyRollbackSnapshot } from "./rollback.mjs";
import { publishToFastKv } from "./train.mjs";
//#region src/services/deploy/rollback-flow.ts
async function fetchRollbackHistory(input) {
return fetchConfigHistory({
accountId: input.account,
gatewayId: input.domain,
registry: input.registry,
limit: input.limit
});
}
/** The live config, or undefined when the registry read fails (an unknown
* live state never blocks a rollback — the snapshot publish is idempotent). */
async function fetchLiveConfig(input) {
try {
return await fetchBosConfigFromFastKv(`bos://${input.account}/${input.domain}`, input.registry);
} catch {
return;
}
}
function isSnapshotLive(targetValue, liveValue) {
return JSON.stringify(liveValue) === JSON.stringify(targetValue);
}
/** Stamp + republish the target snapshot verbatim. Callers own verification:
* the smoke protocol refuses unverified targets via
* `rollbackToPreviousSnapshot`; the command runs its two-stage check and
* passes `skipVerify` once it has vetted (or --forced) the snapshot. */
async function publishRollbackSnapshot(targetValue, input, opts) {
if (!opts?.skipVerify) {
const verification = await verifyRollbackSnapshot(targetValue);
if (!verification.ok && verification.verifiable) return {
ok: false,
registryUrl: "",
error: "rollback refused — a pinned slot's bytes are gone or no longer match their SRI"
};
}
const payload = buildRollbackPayload(BosConfigSchema.parse(targetValue), (/* @__PURE__ */ new Date()).toISOString());
const result = await publishToFastKv({
bosConfig: payload,
runtimeConfig: input.runtimeConfig,
configDir: input.configDir,
env: input.env,
build: false,
dryRun: input.dryRun ?? false,
verbose: input.verbose ?? false,
packages: "all",
network: input.network,
privateKey: input.privateKey,
wallet: input.wallet ?? false,
registry: input.registry,
exactPayload: true
});
if (result.status === "dry-run") return {
ok: true,
registryUrl: result.registryUrl,
dryRun: true
};
if (result.status === "error") return {
ok: false,
registryUrl: result.registryUrl,
error: `rollback publish failed: ${result.error ?? result.status}`
};
return {
ok: true,
registryUrl: result.registryUrl,
txHash: result.txHash
};
}
/** The post-publish smoke failure protocol (ADR 0021): roll the registry
* config back to the previous snapshot — a red boot gate must never leave a
* new config live against an old image. */
async function rollbackToPreviousSnapshot(input) {
let history;
try {
history = await fetchRollbackHistory({
account: input.account,
domain: input.domain,
registry: input.registry,
limit: 20
});
} catch (error) {
return {
ok: false,
registryUrl: "",
error: `fetching publish history failed: ${error instanceof Error ? error.message : String(error)}`
};
}
const previous = history[1];
if (!previous) return {
ok: false,
registryUrl: "",
error: "no previous snapshot in the publish history — nothing to roll back to"
};
const result = await publishRollbackSnapshot(previous.value, input);
if (result.ok) return {
ok: true,
blockHeight: String(previous.blockHeight),
registryUrl: result.registryUrl,
txHash: result.txHash
};
return result;
}
//#endregion
export { fetchLiveConfig, fetchRollbackHistory, isSnapshotLive, publishRollbackSnapshot, rollbackToPreviousSnapshot };
//# sourceMappingURL=rollback-flow.mjs.map