diff --git a/__tests__/search.test.ts b/__tests__/search.test.ts index 4a8c3c6..bebcad9 100644 --- a/__tests__/search.test.ts +++ b/__tests__/search.test.ts @@ -1,4 +1,5 @@ -import { askContent, searchContent, searchSpaces, searchUsers } from "../src/modules/search"; +import { askContent, matchUsers, searchContent, searchSpaces, searchUsers } from "../src/modules/search"; +import type { MatchUsersResponse } from "../src/modules/search/matchUsers"; import { makeClient } from "./helpers/mockClient"; describe("node-sdk search — request shaping", () => { @@ -49,6 +50,36 @@ describe("node-sdk search — request shaping", () => { { params: { spaceReputationId: "rep1", spaceReputationDescendants: false } }, ); }); + + it("matchUsers POSTs the full body to /match/users", async () => { + const { client, projectInstance } = makeClient(); + await matchUsers(client, { + mode: "directed", + query: "biotech", + limit: 10, + spaceId: "space-1", + includeChildSpaces: true, + includeSampleContent: true, + excludeSelf: false, + }); + expect(projectInstance.post).toHaveBeenCalledWith("/match/users", { + mode: "directed", + query: "biotech", + limit: 10, + spaceId: "space-1", + includeChildSpaces: true, + includeSampleContent: true, + excludeSelf: false, + }); + }); + + it("matchUsers passes a minimal passive body through unchanged", async () => { + const { client, projectInstance } = makeClient(); + await matchUsers(client, { mode: "passive" }); + expect(projectInstance.post).toHaveBeenCalledWith("/match/users", { + mode: "passive", + }); + }); }); describe("node-sdk search — response mapping", () => { @@ -81,4 +112,27 @@ describe("node-sdk search — response mapping", () => { askContent(client, { query: "what is this space about?" }), ).resolves.toEqual(result); }); + + it("matchUsers returns the { results } envelope from the response body", async () => { + const { client, projectInstance } = makeClient(); + const envelope: MatchUsersResponse = { + results: [ + { + user: { id: "u1" } as MatchUsersResponse["results"][number]["user"], + score: 1.5, + matchedFacets: [ + { + similarity: 0.7, + askerFacet: { id: "af", hotness: 3 }, + candidateFacet: { id: "cf", hotness: 4 }, + }, + ], + }, + ], + }; + projectInstance.post.mockResolvedValueOnce({ data: envelope }); + const res = await matchUsers(client, { mode: "passive" }); + expect(res).toEqual(envelope); + expect(res.results[0].matchedFacets[0].candidateFacet.hotness).toBe(4); + }); }); diff --git a/src/modules/search/index.ts b/src/modules/search/index.ts index e305f7e..ed12816 100644 --- a/src/modules/search/index.ts +++ b/src/modules/search/index.ts @@ -2,3 +2,4 @@ export { searchContent } from "./searchContent"; export { searchUsers } from "./searchUsers"; export { searchSpaces } from "./searchSpaces"; export { askContent } from "./askContent"; +export { matchUsers } from "./matchUsers"; diff --git a/src/modules/search/matchUsers.ts b/src/modules/search/matchUsers.ts new file mode 100644 index 0000000..d271dd2 --- /dev/null +++ b/src/modules/search/matchUsers.ts @@ -0,0 +1,52 @@ +import { SublayHttpClient } from "../../core/client"; +import { User } from "../../interfaces/User"; + +export interface MatchUsersProps { + mode: "passive" | "directed"; + query?: string; + limit?: number; + spaceId?: string; + includeChildSpaces?: boolean; + includeSampleContent?: boolean; + excludeSelf?: boolean; +} + +export interface MatchFacetRef { + id: string; + hotness: number; +} + +export interface SampleContent { + sourceType: "entity" | "comment" | "message"; + recordId: string; + content: string; + similarity: number; +} + +export interface MatchedFacet { + similarity: number; + askerFacet?: MatchFacetRef; + candidateFacet: MatchFacetRef; + sampleContent?: SampleContent[]; +} + +export interface UserMatchResult { + user: User; + score: number; + matchedFacets: MatchedFacet[]; +} + +export interface MatchUsersResponse { + results: UserMatchResult[]; +} + +export async function matchUsers( + client: SublayHttpClient, + data: MatchUsersProps +): Promise { + const response = await client.projectInstance.post( + "/match/users", + data + ); + return response.data; +}