openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
259 lines (258 loc) • 9.6 kB
JavaScript
import { r as resolveMissingRequestedScope } from "./operator-scope-compat-Ci6GBcmU.mjs";
import { t as resolveNodePairApprovalScopes } from "./node-pairing-authz-UuidBiYT.mjs";
import { C as readDevicePairingStoreStateFromDatabase, T as updatePairedDeviceInTransaction, a as resolveNodePairingGeneration, j as requestDevicePairingMutationAdmission, o as resolveNodePairingState, t as clearNodePairingGenerationState, x as persistDevicePairingStoreState } from "./device-pairing-identity-f0QUXRJo.mjs";
import { c as toPublicPendingRequest, i as samePendingApprovalSurface, o as toPairedNode, r as refreshPendingNodeSurface, s as toPendingSnapshot, t as buildPendingNodeSurface } from "./device-pairing-node.records-Fl7vnrHF.mjs";
import { t as devicePairingMutation } from "./device-pairing-dispatch.worker-NIcSJbfk.mjs";
//#region src/infra/device-pairing-node.worker.ts
function mutatePairedDevices(database, operate) {
const state = readDevicePairingStoreStateFromDatabase(database.db);
const result = operate(state.pairedByDeviceId);
if (result.persist) persistDevicePairingStoreState(state, void 0, "paired");
return result.value;
}
function updateNodeSurface(input, update, matches = () => true) {
const { nodeId, expectedPairingGeneration } = input;
return updatePairedDeviceInTransaction(nodeId, void 0, (device) => {
const surface = device?.nodeSurface;
if (!device || !surface || expectedPairingGeneration.nodeId !== device.deviceId || resolveNodePairingGeneration(device)?.key !== expectedPairingGeneration.key || !matches(surface)) return { value: false };
requestDevicePairingMutationAdmission({
kind: "node-surface",
nodeId: device.deviceId,
pairingGeneration: expectedPairingGeneration.key
});
return {
value: true,
patch: { nodeSurface: update(surface) }
};
});
}
const nodePairingOperations = {
"node.request": devicePairingMutation((input, { database }) => {
const { req, nowMs } = input;
const nodeId = req.nodeId.trim();
if (!nodeId) throw new Error("nodeId required");
return mutatePairedDevices(database, (paired) => {
const device = paired[nodeId];
if (!device) throw new Error("node pairing requires a paired device");
requestDevicePairingMutationAdmission({
kind: "node-surface",
nodeId
});
const request = {
...req,
nodeId,
silent: req.silent && !device.nodeSurface
};
const existing = device.pendingNodeSurface;
if (existing && samePendingApprovalSurface(existing, request)) {
const refreshed = refreshPendingNodeSurface(existing, request, nowMs);
device.pendingNodeSurface = refreshed;
return {
value: {
status: "pending",
request: toPublicPendingRequest(device, refreshed),
created: false
},
persist: true
};
}
const replacement = buildPendingNodeSurface({
req: request,
nowMs
});
device.pendingNodeSurface = replacement;
const superseded = existing ? [{
requestId: existing.requestId,
nodeId
}] : [];
return {
value: {
status: "pending",
request: toPublicPendingRequest(device, replacement),
created: true,
...superseded.length > 0 ? { superseded } : {}
},
persist: true
};
});
}),
"node.finalizeCleanup": devicePairingMutation((input, { database }) => {
const { observed } = input;
return mutatePairedDevices(database, (paired) => {
const device = paired[observed.nodeId.trim()];
const pending = device?.pendingNodeSurface;
if (!device || !pending || observed.requestId !== pending.requestId || observed.revision !== pending.revision) return {
value: [],
persist: false
};
requestDevicePairingMutationAdmission({
kind: "node-pending",
...toPendingSnapshot(device, pending)
});
delete device.pendingNodeSurface;
return {
value: [{
requestId: pending.requestId,
nodeId: device.deviceId
}],
persist: true
};
});
}),
"node.approve": devicePairingMutation((input, { database }) => {
const { requestId, callerScopes, nowMs } = input;
return mutatePairedDevices(database, (paired) => {
const device = Object.values(paired).find((entry) => entry.pendingNodeSurface?.requestId === requestId);
const pending = device?.pendingNodeSurface;
if (!device || !pending || input.initialOnly && device.nodeSurface) return {
value: null,
persist: false
};
requestDevicePairingMutationAdmission({
kind: "node-pending",
...toPendingSnapshot(device, pending)
});
const missingScope = resolveMissingRequestedScope({
role: "operator",
requestedScopes: resolveNodePairApprovalScopes(pending.commands ?? []),
allowedScopes: callerScopes ?? []
});
if (missingScope) return {
value: {
status: "forbidden",
missingScope
},
persist: false
};
const previousPairingGeneration = resolveNodePairingGeneration(device);
const now = Math.max(nowMs, (device.nodeSurface?.approvedAtMs ?? -1) + 1);
device.nodeSurface = {
displayName: device.nodeSurface?.displayName ?? pending.displayName,
version: pending.version,
coreVersion: pending.coreVersion,
uiVersion: pending.uiVersion,
modelIdentifier: pending.modelIdentifier,
caps: pending.caps,
commands: pending.commands,
permissions: pending.permissions,
bins: device.nodeSurface?.bins,
createdAtMs: device.nodeSurface?.createdAtMs ?? now,
approvedAtMs: now,
lastConnectedAtMs: device.nodeSurface?.lastConnectedAtMs,
lastHostStats: device.nodeSurface?.lastHostStats
};
delete device.pendingNodeSurface;
const nextPairingState = resolveNodePairingState(device);
const nextPairingGeneration = nextPairingState?.generation?.key;
if (!nextPairingState || !nextPairingGeneration) return {
value: null,
persist: false
};
clearNodePairingGenerationState(device, previousPairingGeneration);
const node = toPairedNode(device);
return node ? {
value: {
requestId,
node,
pairingIdentity: nextPairingState.identity.key,
nextPairingGeneration,
...previousPairingGeneration ? { previousPairingGeneration: previousPairingGeneration.key } : {}
},
persist: true
} : {
value: null,
persist: false
};
});
}),
"node.reject": devicePairingMutation((input, { database }) => {
const { requestId } = input;
return mutatePairedDevices(database, (paired) => {
const device = Object.values(paired).find((entry) => entry.pendingNodeSurface?.requestId === requestId);
const pending = device?.pendingNodeSurface;
if (!device || !pending) return {
value: null,
persist: false
};
requestDevicePairingMutationAdmission({
kind: "node-pending",
...toPendingSnapshot(device, pending)
});
delete device.pendingNodeSurface;
return {
value: {
requestId,
nodeId: device.deviceId
},
persist: true
};
});
}),
"node.rename": devicePairingMutation((input, { database }) => {
const displayName = input.displayName.trim();
if (!displayName) throw new Error("displayName required");
return mutatePairedDevices(database, (paired) => {
const device = paired[input.nodeId.trim()];
if (!device?.nodeSurface) return {
value: null,
persist: false
};
requestDevicePairingMutationAdmission({
kind: "node-surface",
nodeId: device.deviceId,
pairingGeneration: resolveNodePairingGeneration(device)?.key
});
device.nodeSurface = {
...device.nodeSurface,
displayName
};
return {
value: toPairedNode(device),
persist: true
};
});
}),
"node.recordConnection": devicePairingMutation((input) => {
const { nodeId, connectedAtMs, expectedPairingGeneration } = input;
return updatePairedDeviceInTransaction(nodeId, void 0, (device) => {
if (!device?.nodeSurface || expectedPairingGeneration && (expectedPairingGeneration.nodeId !== device.deviceId || resolveNodePairingGeneration(device)?.key !== expectedPairingGeneration.key)) return { value: { recorded: false } };
requestDevicePairingMutationAdmission({
kind: "node-surface",
nodeId: device.deviceId,
pairingGeneration: resolveNodePairingGeneration(device)?.key
});
const firstConnection = device.nodeSurface.lastConnectedAtMs === void 0;
const lastConnectedAtMs = Math.max(device.nodeSurface.lastConnectedAtMs ?? connectedAtMs, connectedAtMs);
const clearsDisconnect = device.nodeSurface.lastDisconnectedAtMs !== void 0 && connectedAtMs > device.nodeSurface.lastDisconnectedAtMs;
return {
value: {
recorded: true,
firstConnection
},
patch: { nodeSurface: {
...device.nodeSurface,
lastConnectedAtMs,
...clearsDisconnect ? { lastDisconnectedAtMs: void 0 } : {}
} }
};
});
}),
"node.recordDisconnection": devicePairingMutation((input) => updateNodeSurface(input, (surface) => ({
...surface,
lastDisconnectedAtMs: Math.max(surface.lastDisconnectedAtMs ?? input.disconnectedAtMs, input.disconnectedAtMs)
}), (surface) => surface.lastConnectedAtMs === input.connectedAtMs && !(input.disconnectedAtMs < input.connectedAtMs))),
"node.recordHostStats": devicePairingMutation((input) => updateNodeSurface(input, (surface) => ({
...surface,
lastHostStats: input.hostStats
}))),
"node.updateBins": devicePairingMutation((input) => updateNodeSurface(input, (surface) => ({
...surface,
bins: input.bins
}))),
"node.updateSessionHost": devicePairingMutation((input) => updateNodeSurface(input, (surface) => ({
...surface,
sessionHost: input.sessionHost
})))
};
//#endregion
export { nodePairingOperations };