refactor(core): extract shared dedup helpers
This commit is contained in:
@@ -31,6 +31,7 @@ const mocks = vi.hoisted(() => ({
|
||||
fsLstat: vi.fn(async (..._args: unknown[]) => null as import("node:fs").Stats | null),
|
||||
fsRealpath: vi.fn(async (p: string) => p),
|
||||
fsOpen: vi.fn(async () => ({}) as unknown),
|
||||
writeFileWithinRoot: vi.fn(async () => {}),
|
||||
}));
|
||||
|
||||
vi.mock("../../config/config.js", () => ({
|
||||
@@ -77,6 +78,15 @@ vi.mock("../session-utils.js", () => ({
|
||||
listAgentsForGateway: mocks.listAgentsForGateway,
|
||||
}));
|
||||
|
||||
vi.mock("../../infra/fs-safe.js", async () => {
|
||||
const actual =
|
||||
await vi.importActual<typeof import("../../infra/fs-safe.js")>("../../infra/fs-safe.js");
|
||||
return {
|
||||
...actual,
|
||||
writeFileWithinRoot: mocks.writeFileWithinRoot,
|
||||
};
|
||||
});
|
||||
|
||||
// Mock node:fs/promises – agents.ts uses `import fs from "node:fs/promises"`
|
||||
// which resolves to the module namespace default, so we spread actual and
|
||||
// override the methods we need, plus set `default` explicitly.
|
||||
|
||||
@@ -732,10 +732,19 @@ export const agentsHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
const content = String(params.content ?? "");
|
||||
const relativeWritePath = path.relative(resolvedPath.workspaceReal, resolvedPath.ioPath);
|
||||
if (
|
||||
!relativeWritePath ||
|
||||
relativeWritePath.startsWith("..") ||
|
||||
path.isAbsolute(relativeWritePath)
|
||||
) {
|
||||
respondWorkspaceFileUnsafe(respond, name);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await writeFileWithinRoot({
|
||||
rootDir: workspaceDir,
|
||||
relativePath: name,
|
||||
rootDir: resolvedPath.workspaceReal,
|
||||
relativePath: relativeWritePath,
|
||||
data: content,
|
||||
encoding: "utf8",
|
||||
});
|
||||
|
||||
@@ -274,20 +274,7 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const p = params as {
|
||||
nodeId: string;
|
||||
displayName?: string;
|
||||
platform?: string;
|
||||
version?: string;
|
||||
coreVersion?: string;
|
||||
uiVersion?: string;
|
||||
deviceFamily?: string;
|
||||
modelIdentifier?: string;
|
||||
caps?: string[];
|
||||
commands?: string[];
|
||||
remoteIp?: string;
|
||||
silent?: boolean;
|
||||
};
|
||||
const p = params as Parameters<typeof requestNodePairing>[0];
|
||||
await respondUnavailableOnThrow(respond, async () => {
|
||||
const result = await requestNodePairing({
|
||||
nodeId: p.nodeId,
|
||||
@@ -300,6 +287,7 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
modelIdentifier: p.modelIdentifier,
|
||||
caps: p.caps,
|
||||
commands: p.commands,
|
||||
permissions: p.permissions,
|
||||
remoteIp: p.remoteIp,
|
||||
silent: p.silent,
|
||||
});
|
||||
|
||||
@@ -17,6 +17,27 @@ async function invokeSecretsReload(params: {
|
||||
});
|
||||
}
|
||||
|
||||
async function invokeSecretsResolve(params: {
|
||||
handlers: ReturnType<typeof createSecretsHandlers>;
|
||||
respond: ReturnType<typeof vi.fn>;
|
||||
commandName: unknown;
|
||||
targetIds: unknown;
|
||||
}) {
|
||||
await params.handlers["secrets.resolve"]({
|
||||
req: { type: "req", id: "1", method: "secrets.resolve" },
|
||||
params: {
|
||||
commandName: params.commandName,
|
||||
targetIds: params.targetIds,
|
||||
},
|
||||
client: null,
|
||||
isWebchatConnect: () => false,
|
||||
respond: params.respond as unknown as Parameters<
|
||||
ReturnType<typeof createSecretsHandlers>["secrets.resolve"]
|
||||
>[0]["respond"],
|
||||
context: {} as never,
|
||||
});
|
||||
}
|
||||
|
||||
describe("secrets handlers", () => {
|
||||
function createHandlers(overrides?: {
|
||||
reloadSecrets?: () => Promise<{ warningCount: number }>;
|
||||
@@ -73,13 +94,11 @@ describe("secrets handlers", () => {
|
||||
});
|
||||
const handlers = createHandlers({ resolveSecrets });
|
||||
const respond = vi.fn();
|
||||
await handlers["secrets.resolve"]({
|
||||
req: { type: "req", id: "1", method: "secrets.resolve" },
|
||||
params: { commandName: "memory status", targetIds: ["talk.apiKey"] },
|
||||
client: null,
|
||||
isWebchatConnect: () => false,
|
||||
await invokeSecretsResolve({
|
||||
handlers,
|
||||
respond,
|
||||
context: {} as never,
|
||||
commandName: "memory status",
|
||||
targetIds: ["talk.apiKey"],
|
||||
});
|
||||
expect(resolveSecrets).toHaveBeenCalledWith({
|
||||
commandName: "memory status",
|
||||
@@ -96,13 +115,11 @@ describe("secrets handlers", () => {
|
||||
it("rejects invalid secrets.resolve params", async () => {
|
||||
const handlers = createHandlers();
|
||||
const respond = vi.fn();
|
||||
await handlers["secrets.resolve"]({
|
||||
req: { type: "req", id: "1", method: "secrets.resolve" },
|
||||
params: { commandName: "", targetIds: "bad" },
|
||||
client: null,
|
||||
isWebchatConnect: () => false,
|
||||
await invokeSecretsResolve({
|
||||
handlers,
|
||||
respond,
|
||||
context: {} as never,
|
||||
commandName: "",
|
||||
targetIds: "bad",
|
||||
});
|
||||
expect(respond).toHaveBeenCalledWith(
|
||||
false,
|
||||
@@ -117,13 +134,11 @@ describe("secrets handlers", () => {
|
||||
const resolveSecrets = vi.fn();
|
||||
const handlers = createHandlers({ resolveSecrets });
|
||||
const respond = vi.fn();
|
||||
await handlers["secrets.resolve"]({
|
||||
req: { type: "req", id: "1", method: "secrets.resolve" },
|
||||
params: { commandName: "memory status", targetIds: ["talk.apiKey", 12] },
|
||||
client: null,
|
||||
isWebchatConnect: () => false,
|
||||
await invokeSecretsResolve({
|
||||
handlers,
|
||||
respond,
|
||||
context: {} as never,
|
||||
commandName: "memory status",
|
||||
targetIds: ["talk.apiKey", 12],
|
||||
});
|
||||
expect(resolveSecrets).not.toHaveBeenCalled();
|
||||
expect(respond).toHaveBeenCalledWith(
|
||||
@@ -140,13 +155,11 @@ describe("secrets handlers", () => {
|
||||
const resolveSecrets = vi.fn();
|
||||
const handlers = createHandlers({ resolveSecrets });
|
||||
const respond = vi.fn();
|
||||
await handlers["secrets.resolve"]({
|
||||
req: { type: "req", id: "1", method: "secrets.resolve" },
|
||||
params: { commandName: "memory status", targetIds: ["unknown.target"] },
|
||||
client: null,
|
||||
isWebchatConnect: () => false,
|
||||
await invokeSecretsResolve({
|
||||
handlers,
|
||||
respond,
|
||||
context: {} as never,
|
||||
commandName: "memory status",
|
||||
targetIds: ["unknown.target"],
|
||||
});
|
||||
expect(resolveSecrets).not.toHaveBeenCalled();
|
||||
expect(respond).toHaveBeenCalledWith(
|
||||
@@ -167,13 +180,11 @@ describe("secrets handlers", () => {
|
||||
});
|
||||
const handlers = createHandlers({ resolveSecrets });
|
||||
const respond = vi.fn();
|
||||
await handlers["secrets.resolve"]({
|
||||
req: { type: "req", id: "1", method: "secrets.resolve" },
|
||||
params: { commandName: "memory status", targetIds: ["talk.apiKey"] },
|
||||
client: null,
|
||||
isWebchatConnect: () => false,
|
||||
await invokeSecretsResolve({
|
||||
handlers,
|
||||
respond,
|
||||
context: {} as never,
|
||||
commandName: "memory status",
|
||||
targetIds: ["talk.apiKey"],
|
||||
});
|
||||
expect(respond).toHaveBeenCalledWith(
|
||||
false,
|
||||
|
||||
Reference in New Issue
Block a user