/** * Remote Node API functions for fetching data from remote nodes via the proxy. * All functions route through /api/proxy/:nodeId/... when a remote node is targeted. */ import type { NodeProjectMappingInput, ProjectInfo } from "./api"; import type { ProjectHealth, ProjectNodePathMapping, Task } from "@fusion/core"; import { api, proxyApi, upsertProjectPathMapping } from "./api"; /** Health information for a remote node */ export interface RemoteNodeHealth { status: string; version: string; nodeId: string; } /** Fetch health information from a remote node */ export async function fetchRemoteNodeHealth(nodeId: string): Promise { return proxyApi("/health", { nodeId }); } /** Fetch all projects from a remote node */ export async function fetchRemoteNodeProjects(nodeId: string): Promise { return proxyApi("/projects", { nodeId }); } /** Fetch tasks from a specific project on a remote node */ export async function fetchRemoteNodeTasks( nodeId: string, projectId: string, searchQuery?: string, ): Promise { const params = new URLSearchParams({ projectId }); if (searchQuery && searchQuery.trim()) { params.set("q", searchQuery.trim()); } return proxyApi(`/tasks?${params.toString()}`, { nodeId }); } /** Fetch project health from a remote node */ export async function fetchRemoteNodeProjectHealth( nodeId: string, projectId: string, ): Promise { return proxyApi(`/project-health?projectId=${encodeURIComponent(projectId)}`, { nodeId, }); } // ── Node Settings Sync API ────────────────────────────────────────────────────── /** Settings scopes returned by GET /api/nodes/:id/settings */ export interface NodeSettingsScopes { global: Record; project: Record; } /** Result from settings push/pull operations */ export interface NodeSettingsSyncResult { success: boolean; syncedFields?: string[]; appliedFields?: string[]; skippedFields?: string[]; error?: string; } /** Sync status returned by GET /api/nodes/:id/settings/sync-status */ export interface NodeSettingsSyncStatus { lastSyncAt: string | null; lastSyncDirection: string | null; localUpdatedAt: string; remoteReachable: boolean; diff: { global: string[]; project: string[]; }; /** Overall auth credential sync state: "match" if credentials match between local and remote, * "differs" if they differ, "not-synced" if auth sync has never been performed. */ authMatch?: "match" | "differs" | "not-synced"; /** Per-provider auth match details. Map of provider name to match status. */ authDiff?: Record; } /** Result from auth sync operation */ export interface NodeAuthSyncResult { success: boolean; syncedProviders: string[]; } /** Fetch settings from a remote node */ export async function fetchNodeSettings(nodeId: string): Promise { return api(`/nodes/${encodeURIComponent(nodeId)}/settings`); } /** Push local settings to a remote node */ export async function pushNodeSettings(nodeId: string): Promise { return api(`/nodes/${encodeURIComponent(nodeId)}/settings/push`, { method: "POST", body: JSON.stringify({}), }); } /** Pull settings from a remote node and apply locally */ export async function pullNodeSettings(nodeId: string): Promise { return api(`/nodes/${encodeURIComponent(nodeId)}/settings/pull`, { method: "POST", body: JSON.stringify({ conflictResolution: "last-write-wins" }), }); } /** Get the sync status for a node (last sync time, diff summary, etc.) */ export async function fetchNodeSettingsSyncStatus(nodeId: string): Promise { return api(`/nodes/${encodeURIComponent(nodeId)}/settings/sync-status`); } /** Synchronize model auth credentials with a remote node */ export async function syncNodeAuth(nodeId: string): Promise { return api(`/nodes/${encodeURIComponent(nodeId)}/auth/sync`, { method: "POST", body: JSON.stringify({}), }); } /** Fetch all project path mappings for a node */ export async function fetchNodeProjectPathMappings(nodeId: string): Promise { return api(`/nodes/${encodeURIComponent(nodeId)}/path-mappings`); } /** Persist one mapping per selected project for a newly-created node. */ export async function persistNodeProjectPathMappings( nodeId: string, projectMappings: NodeProjectMappingInput[], ): Promise { return Promise.all( projectMappings.map(({ projectId, path }) => upsertProjectPathMapping(projectId, nodeId, path)), ); }