openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
54 lines (53 loc) • 3.62 kB
JavaScript
import { i as getNodeSqliteKysely, r as executeSqliteQueryTakeFirstSync } from "./kysely-sync-BMSZn9yz.mjs";
import { l as runOpenClawStateWriteTransaction } from "./openclaw-state-db-VZFEEleX.mjs";
import { o as recordLegacyMigrationRun } from "./state-migrations.receipts-CG4TZyVG.mjs";
import { n as NODE_DESKTOP_STREAM_COMMAND } from "./node-desktop-stream-BZM2AiRA.mjs";
import { s as withDevicePairingLock } from "./device-pairing-store-readonly-CgfTz2YZ.mjs";
import { C as persistDevicePairingStoreState, T as readDevicePairingStoreStateFromDatabase, a as resolveNodePairingGeneration, t as clearNodePairingGenerationState } from "./device-pairing-identity-cBx6JPcp.mjs";
import "./device-pairing-BGCnp3WV.mjs";
import { randomUUID } from "node:crypto";
//#region src/infra/device-pairing-node-desktop-migration.ts
const MIGRATION_ID = "node-desktop-stream-pairing-defaults-v1";
/** Also applies to old file-backed surfaces imported after the SQLite migration completed. */
function preserveLegacyDesktopStreamOptOut(device, cfg, now) {
const commands = cfg.gateway?.nodes?.commands;
if ([commands?.allow, commands?.deny].some((entries) => entries?.some((command) => command.trim() === "desktop.stream"))) return false;
const surface = device.nodeSurface;
if (!Array.isArray(surface?.commands) || !surface.commands.some((command) => typeof command === "string" && command.trim() === "desktop.stream")) return false;
if (!surface.commands.every((command) => typeof command === "string") || !Number.isSafeInteger(surface.createdAtMs) || !Number.isSafeInteger(surface.approvedAtMs) || !Number.isSafeInteger(surface.approvedAtMs + 1)) throw new Error(`Cannot migrate malformed desktop approval for node ${device.deviceId}`);
const previousGeneration = resolveNodePairingGeneration(device);
surface.commands = surface.commands.filter((command) => command.trim() !== NODE_DESKTOP_STREAM_COMMAND);
surface.approvedAtMs = Math.max(now, surface.approvedAtMs + 1);
clearNodePairingGenerationState(device, previousGeneration);
if (device.pendingNodeSurface?.commands?.some((command) => command.trim() === "desktop.stream")) {
device.pendingNodeSurface.silent = false;
device.pendingNodeSurface.revision = randomUUID();
}
return true;
}
/** Commit narrowed approvals and the once-per-database receipt together before node admission. */
async function migrateLegacyDesktopStreamOptOuts(cfg, baseDir) {
return await withDevicePairingLock(async () => runOpenClawStateWriteTransaction(({ db }) => {
const receipt = executeSqliteQueryTakeFirstSync(db, getNodeSqliteKysely(db).selectFrom("migration_runs").select("status").where("id", "=", MIGRATION_ID));
if (receipt?.status === "completed") return 0;
if (receipt) throw new Error("Desktop approval migration receipt is incomplete; existing approvals remain unchanged.");
const now = Date.now();
const state = readDevicePairingStoreStateFromDatabase(db);
let retired = 0;
for (const device of Object.values(state.pairedByDeviceId)) if (preserveLegacyDesktopStreamOptOut(device, cfg, now)) retired += 1;
if (retired > 0) persistDevicePairingStoreState(state, baseDir, "paired");
recordLegacyMigrationRun(db, {
runId: MIGRATION_ID,
startedAt: now,
finishedAt: now,
status: "completed",
reportJson: JSON.stringify({ retiredDesktopApprovals: retired })
});
return retired;
}, baseDir ? { env: {
...process.env,
OPENCLAW_STATE_DIR: baseDir
} } : {}, { operationLabel: "preserve legacy desktop stream opt-outs" }));
}
//#endregion
export { preserveLegacyDesktopStreamOptOut as n, migrateLegacyDesktopStreamOptOuts as t };