feat: type the plugin host record, move plugin strings out of core and add lint checks

This commit is contained in:
LukeGus committed 2026-09-29 13:08:39 -05:00
1 parent bba06f7ff6
commit b8bbcd2196
626 files changed
+23884 -4590

No files matched your search

+80 -9
View File
@@ -8,7 +8,11 @@
* The vitest config these run under comes from @termix/plugin-sdk/vitest-preset.
*/
import { LoginMethodError, PluginCapabilityError } from "./backend.js";
import {
LoginMethodError,
PLUGIN_HOST_INPUT_KEYS,
PluginCapabilityError,
} from "./backend.js";
import type {
PluginContext,
PluginDisposables,
@@ -396,6 +400,74 @@ function noopLogger(): PluginLogger {
};
}
const HOST_INPUT_KEYS = new Set<string>(PLUGIN_HOST_INPUT_KEYS);
/** Refuses a key ctx.hosts does not take, the way core does. */
function checkHostInput(input: PluginHostUpdateInput): void {
const unknown = Object.keys(input ?? {}).filter(
(key) => !HOST_INPUT_KEYS.has(key),
);
if (unknown.length > 0) {
throw new Error(`ctx.hosts does not take ${unknown.join(", ")}`);
}
}
function emptyHostRecord(id: number, userId: string): PluginHostRecord {
return {
id,
userId,
syncId: null,
name: null,
ip: "",
port: 22,
username: "",
authType: "password",
credentialId: null,
overrideCredentialUsername: false,
connectionType: "ssh",
tags: null,
folder: null,
parentHostId: null,
pin: false,
notes: null,
jumpHosts: [],
enableSsh: true,
sshPort: null,
statusCheckEnabled: true,
statusCheckInterval: null,
connectionOrigin: null,
sshOptions: {},
pluginSettings: {},
status: null,
localOnly: false,
createdAt: null,
updatedAt: null,
};
}
function applyHostInput(
record: PluginHostRecord,
input: PluginHostUpdateInput,
): PluginHostRecord {
const {
tags,
pluginSettings: _settings,
forceKeyboardInteractive: _fki,
...rest
} = input;
const next: PluginHostRecord = { ...record };
for (const [key, value] of Object.entries(rest)) {
if (value !== undefined)
(next as unknown as Record<string, unknown>)[key] = value;
}
if (tags !== undefined) {
next.tags = Array.isArray(tags) ? tags.join(",") : tags;
}
if (next.jumpHosts === null) next.jumpHosts = [];
if (next.sshOptions === null) next.sshOptions = {};
return next;
}
/**
* A context double good enough to call activate() against in a unit test.
* Nothing here is capability-checked: a test asserting a capability gate
@@ -823,14 +895,12 @@ export function createFakeContext(
create: async (
host: PluginHostCreateInput,
): Promise<PluginHostRecord> => {
checkHostInput(host);
const id = nextHostId++;
const record: PluginHostRecord = {
tags: null,
folder: null,
...host,
id,
userId: actor ?? "unknown",
};
const record = applyHostInput(
emptyHostRecord(id, actor ?? "unknown"),
host,
);
hostRecordsById.set(id, record);
return record;
},
@@ -838,9 +908,10 @@ export function createFakeContext(
hostId: number,
patch: PluginHostUpdateInput,
): Promise<PluginHostRecord | null> => {
checkHostInput(patch);
const existing = hostRecordsById.get(hostId);
if (!existing) return null;
const updated = { ...existing, ...patch };
const updated = applyHostInput(existing, patch);
hostRecordsById.set(hostId, updated);
return updated;
},