| 1 | import type { SshDeviceHostConfig } from "@t3tools/contracts"; |
| 2 | |
| 3 | /** Apply one host change without replacing another environment's host list. */ |
| 4 | export function updateDeviceHosts( |
| 5 | hosts: ReadonlyArray<SshDeviceHostConfig>, |
| 6 | host: SshDeviceHostConfig, |
| 7 | remove: boolean, |
| 8 | original = host, |
| 9 | ): ReadonlyArray<SshDeviceHostConfig> { |
| 10 | const sameDestination = (candidate: SshDeviceHostConfig, other: SshDeviceHostConfig) => |
| 11 | candidate.target === other.target && |
| 12 | candidate.port === other.port && |
| 13 | candidate.identityFile === other.identityFile; |
| 14 | const findDestination = (destination: SshDeviceHostConfig) => { |
| 15 | const matches = hosts.filter((candidate) => sameDestination(candidate, destination)); |
| 16 | if (matches.length > 1) { |
| 17 | throw new Error( |
| 18 | "Multiple hosts match this SSH destination. Select the environment to edit its hosts.", |
| 19 | ); |
| 20 | } |
| 21 | return matches[0]; |
| 22 | }; |
| 23 | // A retry can encounter the updated destination on an environment that |
| 24 | // already saved, including one with a different environment-local host ID. |
| 25 | const existing = |
| 26 | hosts.find((candidate) => candidate.id === original.id) ?? |
| 27 | findDestination(original) ?? |
| 28 | (remove ? undefined : findDestination(host)); |
| 29 | if (remove) return hosts.filter((candidate) => candidate.id !== existing?.id); |
| 30 | return existing |
| 31 | ? hosts.map((candidate) => |
| 32 | candidate.id === existing.id ? { ...host, id: existing.id } : candidate, |
| 33 | ) |
| 34 | : [...hosts, host]; |
| 35 | } |