60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
import type { CanvasNode } from "@/types/canvas";
|
|
|
|
export type PendingCanvasAgentTarget = {
|
|
nodeId?: string | null;
|
|
requestedAt?: number | null;
|
|
};
|
|
|
|
const DEFAULT_PENDING_TARGET_MAX_AGE_MS = 10 * 60 * 1000;
|
|
|
|
function normalizeNodeId(value: unknown) {
|
|
return typeof value === "string" ? value.trim() : "";
|
|
}
|
|
|
|
export function resolvePendingCanvasAgentTargetNode(params: {
|
|
nodes: CanvasNode[];
|
|
pendingTarget?: PendingCanvasAgentTarget | null;
|
|
now?: number;
|
|
maxAgeMs?: number;
|
|
isEligibleNode?: (node: CanvasNode) => boolean;
|
|
}) {
|
|
const nodeId = normalizeNodeId(params.pendingTarget?.nodeId);
|
|
if (!nodeId) return null;
|
|
|
|
const requestedAt = Number(params.pendingTarget?.requestedAt || 0);
|
|
const now = Number(params.now ?? Date.now());
|
|
const maxAgeMs = Math.max(
|
|
0,
|
|
Number(params.maxAgeMs ?? DEFAULT_PENDING_TARGET_MAX_AGE_MS)
|
|
);
|
|
if (
|
|
Number.isFinite(requestedAt) &&
|
|
requestedAt > 0 &&
|
|
Number.isFinite(now) &&
|
|
now - requestedAt > maxAgeMs
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
const node = params.nodes.find((item) => item.id === nodeId) || null;
|
|
if (!node) return null;
|
|
if (params.isEligibleNode && !params.isEligibleNode(node)) return null;
|
|
return node;
|
|
}
|
|
|
|
export function mergePendingCanvasAgentTargetNodeIds(params: {
|
|
selectedNodeIds: string[];
|
|
pendingTargetNodeId?: string | null;
|
|
maxItems?: number;
|
|
}) {
|
|
const maxItems = Math.max(1, Number(params.maxItems || 20));
|
|
return Array.from(
|
|
new Set(
|
|
[
|
|
...params.selectedNodeIds,
|
|
normalizeNodeId(params.pendingTargetNodeId),
|
|
].filter(Boolean)
|
|
)
|
|
).slice(0, maxItems);
|
|
}
|