feat: finish the fleets plugin, add ctx.hosts and host-commands SDK (B4)

This commit is contained in:
LukeGus committed 2026-09-23 13:10:18 -05:00
1 parent 37c015a760
commit c381955ed0
43 files changed
+835 -1999

No files matched your search

@@ -21,7 +21,6 @@ import { HostFolderRepository } from "./host-folder-repository.js";
import { HostHealthRepository } from "./host-health-repository.js";
import { HostMetricsHistoryRepository } from "./host-metrics-history-repository.js";
import { HostMetricsPreferenceRepository } from "./host-metrics-preference-repository.js";
import { ProxmoxNodeHistoryRepository } from "./proxmox-node-history-repository.js";
import { HostRepository } from "./host-repository.js";
import { HostResolutionRepository } from "./host-resolution-repository.js";
import { HostSidebarPreferenceRepository } from "./host-sidebar-preference-repository.js";
@@ -283,15 +282,6 @@ export function createCurrentHostMetricsPreferenceRepository(): HostMetricsPrefe
);
}
export function createCurrentProxmoxNodeHistoryRepository(): ProxmoxNodeHistoryRepository {
return new ProxmoxNodeHistoryRepository(
createCurrentRepositoryContext(),
createCurrentRepositoryLazyWriteHook(
"proxmox_node_history_repository_write",
),
);
}
export function createCurrentHostRepository(): HostRepository {
return new HostRepository(
createCurrentRepositoryContext(),
@@ -17,7 +17,6 @@ export interface HostBulkUpdateState {
id: number;
statsConfig: string | null;
credentialId: number | null;
proxmoxConfig: string | null;
}
export class HostRepository {
@@ -103,19 +102,6 @@ export class HostRepository {
return DataCrypto.decryptRecord("ssh_data", row, userId, userDataKey);
}
async listProxmoxEnabled(): Promise<
Pick<HostRecord, "id" | "userId" | "proxmoxConfig">[]
> {
return this.context.drizzle
.select({
id: hosts.id,
userId: hosts.userId,
proxmoxConfig: hosts.proxmoxConfig,
})
.from(hosts)
.where(eq(hosts.enableProxmox, true));
}
async listByUserId(userId: string): Promise<HostRecord[]> {
return this.context.drizzle
.select()
@@ -248,7 +234,6 @@ export class HostRepository {
id: hosts.id,
statsConfig: hosts.statsConfig,
credentialId: hosts.credentialId,
proxmoxConfig: hosts.proxmoxConfig,
})
.from(hosts)
.where(and(inArray(hosts.id, hostIds), eq(hosts.userId, userId)));
@@ -89,6 +89,29 @@ export class PluginSettingsRepository {
);
}
/**
* Every row across all scope ids for one plugin/scope/key, regardless of
* owner. For a plugin's own background scan (auto-sync, polling) that needs
* to find every host with a setting enabled, across every user, before it
* knows which actor to run as.
*/
async listByKey(
pluginId: string,
scope: PluginSettingsScope,
key: string,
): Promise<PluginSettingsRecord[]> {
return this.context.drizzle
.select()
.from(pluginSettings)
.where(
and(
eq(pluginSettings.pluginId, pluginId),
eq(pluginSettings.scope, scope),
eq(pluginSettings.key, key),
),
);
}
async set(
pluginId: string,
scope: PluginSettingsScope,
@@ -1,68 +0,0 @@
import { and, asc, eq, gte, lt, lte } from "drizzle-orm";
import { proxmoxNodeHistory } from "../db/schema.js";
import type { DatabaseContext } from "./database-context.js";
import { sqlTimestampDaysAgo } from "./sql-timestamp.js";
export type ProxmoxNodeHistoryRecord = typeof proxmoxNodeHistory.$inferSelect;
export interface ProxmoxNodeHistoryCreateInput {
hostId: number;
cpuPercent?: number | null;
memPercent?: number | null;
diskPercent?: number | null;
netRxBytes?: number | null;
netTxBytes?: number | null;
}
export class ProxmoxNodeHistoryRepository {
constructor(
private readonly context: DatabaseContext,
private readonly onWrite?: () => void | Promise<void>,
) {}
async create(input: ProxmoxNodeHistoryCreateInput): Promise<void> {
await this.context.drizzle.insert(proxmoxNodeHistory).values({
hostId: input.hostId,
cpuPercent: input.cpuPercent,
memPercent: input.memPercent,
diskPercent: input.diskPercent,
netRxBytes: input.netRxBytes,
netTxBytes: input.netTxBytes,
});
await this.afterWrite();
}
async pruneOlderThan(hostId: number, retentionDays: number): Promise<void> {
await this.context.drizzle
.delete(proxmoxNodeHistory)
.where(
and(
eq(proxmoxNodeHistory.hostId, hostId),
lt(proxmoxNodeHistory.ts, sqlTimestampDaysAgo(retentionDays)),
),
);
}
async listRange(
hostId: number,
fromTs: string,
toTs: string,
): Promise<ProxmoxNodeHistoryRecord[]> {
return this.context.drizzle
.select()
.from(proxmoxNodeHistory)
.where(
and(
eq(proxmoxNodeHistory.hostId, hostId),
gte(proxmoxNodeHistory.ts, fromTs),
lte(proxmoxNodeHistory.ts, toTs),
),
)
.orderBy(asc(proxmoxNodeHistory.ts));
}
private async afterWrite(): Promise<void> {
await this.onWrite?.();
}
}