UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1 lines • 7.21 kB
{"version":3,"file":"rollback-flow.cjs","names":["fetchConfigHistory","fetchBosConfigFromFastKv","verifyRollbackSnapshot","buildRollbackPayload","BosConfigSchema","publishToFastKv"],"sources":["../../../src/services/deploy/rollback-flow.ts"],"sourcesContent":["import { type BosConfigInput, BosConfigSchema, type RuntimeConfig } from \"../../types\";\nimport {\n type ConfigHistoryEntry,\n fetchBosConfigFromFastKv,\n fetchConfigHistory,\n} from \"../registry/fastkv\";\nimport { buildRollbackPayload, verifyRollbackSnapshot } from \"./rollback\";\nimport { publishToFastKv } from \"./train\";\n\n/**\n * The shared rollback flow (ticket #422): the post-publish smoke failure\n * protocol and the `bos rollback` command both stamp `rolledBackFrom` onto\n * the target snapshot and republish it verbatim (`exactPayload`) — one\n * implementation here; the callers differ only in how they pick and vet the\n * target (the command's two-stage verification with --force; the smoke\n * protocol's simple refusal).\n */\n\nexport interface RollbackSnapshotInput {\n account: string;\n domain: string;\n env: \"production\" | \"staging\";\n runtimeConfig: RuntimeConfig | null;\n configDir: string;\n registry?: string;\n network?: \"mainnet\" | \"testnet\";\n privateKey?: string;\n wallet?: boolean;\n verbose?: boolean;\n dryRun?: boolean;\n}\n\nexport interface RollbackSnapshotOutcome {\n ok: boolean;\n registryUrl: string;\n txHash?: string;\n /** the caller passed dryRun — the snapshot was validated but not published */\n dryRun?: boolean;\n error?: string;\n}\n\nexport async function fetchRollbackHistory(input: {\n account: string;\n domain: string;\n registry?: string;\n limit: number;\n}): Promise<ConfigHistoryEntry[]> {\n return fetchConfigHistory({\n accountId: input.account,\n gatewayId: input.domain,\n registry: input.registry,\n limit: input.limit,\n });\n}\n\n/** The live config, or undefined when the registry read fails (an unknown\n * live state never blocks a rollback — the snapshot publish is idempotent). */\nexport async function fetchLiveConfig(input: {\n account: string;\n domain: string;\n registry?: string;\n}): Promise<unknown | undefined> {\n try {\n return await fetchBosConfigFromFastKv<unknown>(\n `bos://${input.account}/${input.domain}`,\n input.registry,\n );\n } catch {\n return undefined;\n }\n}\n\nexport function isSnapshotLive(targetValue: unknown, liveValue: unknown): boolean {\n return JSON.stringify(liveValue) === JSON.stringify(targetValue);\n}\n\n/** Stamp + republish the target snapshot verbatim. Callers own verification:\n * the smoke protocol refuses unverified targets via\n * `rollbackToPreviousSnapshot`; the command runs its two-stage check and\n * passes `skipVerify` once it has vetted (or --forced) the snapshot. */\nexport async function publishRollbackSnapshot(\n targetValue: unknown,\n input: RollbackSnapshotInput,\n opts?: { skipVerify?: boolean },\n): Promise<RollbackSnapshotOutcome> {\n if (!opts?.skipVerify) {\n const verification = await verifyRollbackSnapshot(targetValue as BosConfigInput);\n if (!verification.ok && verification.verifiable) {\n return {\n ok: false,\n registryUrl: \"\",\n error: \"rollback refused — a pinned slot's bytes are gone or no longer match their SRI\",\n };\n }\n }\n\n const payload = buildRollbackPayload(\n BosConfigSchema.parse(targetValue),\n new Date().toISOString(),\n );\n const result = await publishToFastKv({\n bosConfig: payload,\n runtimeConfig: input.runtimeConfig,\n configDir: input.configDir,\n env: input.env,\n build: false,\n dryRun: input.dryRun ?? false,\n verbose: input.verbose ?? false,\n packages: \"all\",\n network: input.network,\n privateKey: input.privateKey,\n wallet: input.wallet ?? false,\n registry: input.registry,\n exactPayload: true,\n });\n if (result.status === \"dry-run\") {\n return { ok: true, registryUrl: result.registryUrl, dryRun: true };\n }\n if (result.status === \"error\") {\n return {\n ok: false,\n registryUrl: result.registryUrl,\n error: `rollback publish failed: ${result.error ?? result.status}`,\n };\n }\n return { ok: true, registryUrl: result.registryUrl, txHash: result.txHash };\n}\n\n/** The post-publish smoke failure protocol (ADR 0021): roll the registry\n * config back to the previous snapshot — a red boot gate must never leave a\n * new config live against an old image. */\nexport async function rollbackToPreviousSnapshot(input: RollbackSnapshotInput): Promise<{\n ok: boolean;\n txHash?: string;\n blockHeight?: string;\n registryUrl: string;\n error?: string;\n}> {\n let history: ConfigHistoryEntry[];\n try {\n history = await fetchRollbackHistory({\n account: input.account,\n domain: input.domain,\n registry: input.registry,\n limit: 20,\n });\n } catch (error) {\n return {\n ok: false,\n registryUrl: \"\",\n error: `fetching publish history failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n\n const previous = history[1];\n if (!previous) {\n return {\n ok: false,\n registryUrl: \"\",\n error: \"no previous snapshot in the publish history — nothing to roll back to\",\n };\n }\n\n const result = await publishRollbackSnapshot(previous.value, input);\n if (result.ok) {\n return {\n ok: true,\n blockHeight: String(previous.blockHeight),\n registryUrl: result.registryUrl,\n txHash: result.txHash,\n };\n }\n return result;\n}\n"],"mappings":";;;;;;AAyCA,eAAsB,qBAAqB,OAKT;CAChC,OAAOA,oDAAmB;EACxB,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,UAAU,MAAM;EAChB,OAAO,MAAM;CACf,CAAC;AACH;;;AAIA,eAAsB,gBAAgB,OAIL;CAC/B,IAAI;EACF,OAAO,MAAMC,0DACX,SAAS,MAAM,QAAQ,GAAG,MAAM,UAChC,MAAM,QACR;CACF,QAAQ;EACN;CACF;AACF;AAEA,SAAgB,eAAe,aAAsB,WAA6B;CAChF,OAAO,KAAK,UAAU,SAAS,MAAM,KAAK,UAAU,WAAW;AACjE;;;;;AAMA,eAAsB,wBACpB,aACA,OACA,MACkC;CAClC,IAAI,CAAC,MAAM,YAAY;EACrB,MAAM,eAAe,MAAMC,wCAAuB,WAA6B;EAC/E,IAAI,CAAC,aAAa,MAAM,aAAa,YACnC,OAAO;GACL,IAAI;GACJ,aAAa;GACb,OAAO;EACT;CAEJ;CAEA,MAAM,UAAUC,sCACdC,8BAAgB,MAAM,WAAW,oBACjC,IAAI,KAAK,EAAC,CAAC,YAAY,CACzB;CACA,MAAM,SAAS,MAAMC,8BAAgB;EACnC,WAAW;EACX,eAAe,MAAM;EACrB,WAAW,MAAM;EACjB,KAAK,MAAM;EACX,OAAO;EACP,QAAQ,MAAM,UAAU;EACxB,SAAS,MAAM,WAAW;EAC1B,UAAU;EACV,SAAS,MAAM;EACf,YAAY,MAAM;EAClB,QAAQ,MAAM,UAAU;EACxB,UAAU,MAAM;EAChB,cAAc;CAChB,CAAC;CACD,IAAI,OAAO,WAAW,WACpB,OAAO;EAAE,IAAI;EAAM,aAAa,OAAO;EAAa,QAAQ;CAAK;CAEnE,IAAI,OAAO,WAAW,SACpB,OAAO;EACL,IAAI;EACJ,aAAa,OAAO;EACpB,OAAO,4BAA4B,OAAO,SAAS,OAAO;CAC5D;CAEF,OAAO;EAAE,IAAI;EAAM,aAAa,OAAO;EAAa,QAAQ,OAAO;CAAO;AAC5E;;;;AAKA,eAAsB,2BAA2B,OAM9C;CACD,IAAI;CACJ,IAAI;EACF,UAAU,MAAM,qBAAqB;GACnC,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,UAAU,MAAM;GAChB,OAAO;EACT,CAAC;CACH,SAAS,OAAO;EACd,OAAO;GACL,IAAI;GACJ,aAAa;GACb,OAAO,oCAAoC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAClG;CACF;CAEA,MAAM,WAAW,QAAQ;CACzB,IAAI,CAAC,UACH,OAAO;EACL,IAAI;EACJ,aAAa;EACb,OAAO;CACT;CAGF,MAAM,SAAS,MAAM,wBAAwB,SAAS,OAAO,KAAK;CAClE,IAAI,OAAO,IACT,OAAO;EACL,IAAI;EACJ,aAAa,OAAO,SAAS,WAAW;EACxC,aAAa,OAAO;EACpB,QAAQ,OAAO;CACjB;CAEF,OAAO;AACT"}