diff --git a/__tests__/space-reputation-serialization.test.ts b/__tests__/space-reputation-serialization.test.ts new file mode 100644 index 0000000..d9c0cb0 --- /dev/null +++ b/__tests__/space-reputation-serialization.test.ts @@ -0,0 +1,133 @@ +import axios from "axios"; + +import { searchContent } from "../src/modules/search"; +import { fetchManyEntities, fetchEntity } from "../src/modules/entities"; +import { fetchUserByForeignId } from "../src/modules/users"; +import { buildSpaceReputationParams } from "../src/core/spaceReputationParams"; +import { makeClient, MockAxiosInstance } from "./helpers/mockClient"; + +/** + * THE serialization regression guard for the `spaceReputation` object (Task 3.4). + * + * The central risk: if the nested `spaceReputation` object is forwarded to axios + * `params` un-normalized, axios bracket-encodes it + * (`spaceReputation%5BspaceId%5D=…`) and the server IGNORES it — so the new + * (primary) form silently no-ops while the deprecated flat props keep working. + * Typecheck and the existing flat-prop tests both stay green when that happens. + * + * These tests pass the OBJECT form, capture the exact `params` object handed to + * the mocked axios instance, serialize it through axios's OWN default param + * serializer (`getUri`), and assert the resulting query string is the FLAT + * `spaceReputationId=…&spaceReputationDescendants=…` — never dropped, never + * bracketed. Each forwarding shape present in the modules is covered: + * - silent-drop (explicit `params: { spaceReputationId, ... }`) → searchContent + * - silent-drop (explicit field-assign params object) → fetchUserByForeignId + * - `params: data` bracket-leak → fetchManyEntities + * - rest-spread `const { id, ...params } = data` bracket-leak → fetchEntity + */ + +// A real axios instance used purely as an oracle for default param +// serialization — the same algorithm the SDK's live instances use. +const serializer = axios.create(); + +/** Serialize a captured `params` object exactly as axios would put it on the wire. */ +function serializeParams(params: unknown): string { + const uri = serializer.getUri({ url: "/x", params: params as any }); + const qIndex = uri.indexOf("?"); + return qIndex === -1 ? "" : uri.slice(qIndex + 1); +} + +/** Pull the `params` object out of the most recent axios get/post mock call. */ +function capturedParams(method: jest.Mock): unknown { + const call = method.mock.calls[method.mock.calls.length - 1]; + // get(path, config) → config is arg 1; post(path, body, config) → config is arg 2. + const config = call.length >= 3 ? call[2] : call[1]; + return (config as { params?: unknown })?.params; +} + +function assertFlatRepQuery(method: jest.Mock) { + const params = capturedParams(method) as Record; + + // The object must never reach axios params un-normalized. + expect(params).not.toHaveProperty("spaceReputation"); + // It must be flattened (not dropped). + expect(params.spaceReputationId).toBe("rep1"); + expect(params.spaceReputationDescendants).toBe(true); + + // And the serialized wire string must be flat, never bracketed. + const query = serializeParams(params); + expect(query).toContain("spaceReputationId=rep1"); + expect(query).toContain("spaceReputationDescendants=true"); + expect(query).not.toContain("spaceReputation%5B"); // spaceReputation[ + expect(query).not.toContain("spaceReputation["); // un-encoded, just in case +} + +describe("space-reputation serialization guard — object form never drops or brackets", () => { + it("silent-drop shape (explicit params object): searchContent", async () => { + const { client, projectInstance } = makeClient(); + await searchContent(client, { + query: "hello", + spaceReputation: { spaceId: "rep1", includeDescendants: true }, + }); + assertFlatRepQuery(projectInstance.post as unknown as jest.Mock); + }); + + it("silent-drop shape (explicit field-assign): fetchUserByForeignId", async () => { + const { client, projectInstance } = makeClient(); + await fetchUserByForeignId(client, { + foreignId: "fid-1", + spaceReputation: { spaceId: "rep1", includeDescendants: true }, + }); + assertFlatRepQuery(projectInstance.get as unknown as jest.Mock); + }); + + it("`params: data` bracket-leak shape: fetchManyEntities", async () => { + const { client, projectInstance } = makeClient(); + await fetchManyEntities(client, { + sortBy: "hot", + spaceReputation: { spaceId: "rep1", includeDescendants: true }, + }); + assertFlatRepQuery(projectInstance.get as unknown as jest.Mock); + // The unrelated param still rides along. + const params = capturedParams(projectInstance.get as unknown as jest.Mock) as Record< + string, + unknown + >; + expect(params.sortBy).toBe("hot"); + }); + + it("rest-spread bracket-leak shape: fetchEntity", async () => { + const { client, projectInstance } = makeClient(); + await fetchEntity(client, { + entityId: "e1", + include: "author", + spaceReputation: { spaceId: "rep1", includeDescendants: true }, + }); + assertFlatRepQuery(projectInstance.get as unknown as jest.Mock); + const params = capturedParams(projectInstance.get as unknown as jest.Mock) as Record< + string, + unknown + >; + expect(params.include).toBe("author"); + expect(params).not.toHaveProperty("entityId"); // path param, not a query param + }); + + it("object form wins over deprecated flat props (precedence)", () => { + const out = buildSpaceReputationParams({ + spaceReputation: { spaceId: "rep1", includeDescendants: true }, + spaceReputationId: "ignored", + spaceReputationDescendants: false, + }); + expect(out).toEqual({ + spaceReputationId: "rep1", + spaceReputationDescendants: true, + }); + }); + + it("`spaceId: \"none\"` flattens to `spaceReputationId=none` without descendants", () => { + const out = buildSpaceReputationParams({ + spaceReputation: { spaceId: "none" }, + }); + expect(out).toEqual({ spaceReputationId: "none" }); + }); +}); diff --git a/src/core/spaceReputationParams.ts b/src/core/spaceReputationParams.ts new file mode 100644 index 0000000..fa4e8c5 --- /dev/null +++ b/src/core/spaceReputationParams.ts @@ -0,0 +1,123 @@ +/** + * Input accepted by {@link buildSpaceReputationParams}: either the new + * `spaceReputation` object or the deprecated flat props. + * + * The flat inputs accept `null` (in addition to `undefined`) so the helper's + * contract matches `@sublay/core` exactly; `null` is treated as unset. node-sdk + * never persists these params, so the `null` tolerance is not strictly required + * here, but matching core is harmless and consistent. + */ +export interface BuildSpaceReputationParamsInput { + spaceReputation?: { + spaceId: string | "none" | "context"; + includeDescendants?: boolean; + }; + /** + * @deprecated Pass `spaceReputation` instead. Accepted for back-compat. + */ + spaceReputationId?: string | null; + /** + * @deprecated Pass `spaceReputation` instead. Accepted for back-compat. + */ + spaceReputationDescendants?: boolean | null; +} + +/** + * Flat output handed to the query-string serializer (axios `params`). Both keys + * are omitted when unset — never bracketed, never nested. + */ +export interface SpaceReputationFlatParams { + spaceReputationId?: string; + spaceReputationDescendants?: boolean; +} + +// Ambient `process` declaration so this file typechecks under the publish build +// tsconfig (which does not pull in @types/node). At runtime node-sdk always runs +// under Node, so `process.env` is present; the `typeof` guard keeps it safe +// anywhere it isn't. +declare const process: + | { env?: Record } + | undefined; + +let bothFormsWarned = false; + +function isProduction(): boolean { + return ( + typeof process !== "undefined" && + !!process.env && + process.env.NODE_ENV === "production" + ); +} + +/** + * Normalize the `spaceReputation` object or the deprecated flat props down to + * the flat query params the server understands + * (`spaceReputationId` / `spaceReputationDescendants`). + * + * **Critical:** this is the only thing that prevents the nested + * `spaceReputation` object from reaching axios `params`, where axios would + * bracket-encode it (`spaceReputation[spaceId]=…`) and the server would ignore + * it — silently no-opping the new (primary) form. Every reputation-consuming + * module must route the object through here and merge only the flat output. + * + * Rules (mirrors the `@sublay/core` helper contract): + * - **Object wins when present.** "Present" means the `spaceReputation` key was + * supplied at all (`spaceReputation !== undefined`) — even `{}` or a partial + * object suppresses the flat props. + * - When **both** the object and a flat prop are supplied, the object wins and a + * one-time dev-only `console.warn` fires (never throws). + * - The flat inputs tolerate `null` (treated as unset → param omitted). + * - Output keys are omitted when unset; the result is always the two flat keys, + * never a bracketed/nested object. + */ +export function buildSpaceReputationParams( + input: BuildSpaceReputationParamsInput +): SpaceReputationFlatParams { + const { spaceReputation, spaceReputationId, spaceReputationDescendants } = + input; + + const objectPresent = spaceReputation !== undefined; + const flatPresent = + (spaceReputationId !== undefined && spaceReputationId !== null) || + (spaceReputationDescendants !== undefined && + spaceReputationDescendants !== null); + + if (objectPresent && flatPresent && !bothFormsWarned && !isProduction()) { + bothFormsWarned = true; + // eslint-disable-next-line no-console + console.warn( + "[Sublay] Both `spaceReputation` and the deprecated flat props " + + "(`spaceReputationId` / `spaceReputationDescendants`) were supplied. " + + "The `spaceReputation` object takes precedence; the flat props are ignored. " + + "Remove the flat props — they are deprecated." + ); + } + + const result: SpaceReputationFlatParams = {}; + + if (objectPresent) { + // Object form chosen. Read from the object; ignore the flat props entirely. + const spaceId = spaceReputation!.spaceId; + if (spaceId !== undefined && spaceId !== null) { + result.spaceReputationId = spaceId; + } + const includeDescendants = spaceReputation!.includeDescendants; + if (includeDescendants !== undefined && includeDescendants !== null) { + result.spaceReputationDescendants = includeDescendants; + } + return result; + } + + // Flat form. `null` is treated as unset (param omitted). + if (spaceReputationId !== undefined && spaceReputationId !== null) { + result.spaceReputationId = spaceReputationId; + } + if ( + spaceReputationDescendants !== undefined && + spaceReputationDescendants !== null + ) { + result.spaceReputationDescendants = spaceReputationDescendants; + } + + return result; +} diff --git a/src/interfaces/SpaceReputation.ts b/src/interfaces/SpaceReputation.ts index 77d2eba..db3bc1c 100644 --- a/src/interfaces/SpaceReputation.ts +++ b/src/interfaces/SpaceReputation.ts @@ -12,7 +12,15 @@ * module). Accept ` | "none"` only; `"context"` is rejected (400). * * Both classes share the same param names and types — only the accepted - * `spaceReputationId` value set (documented in JSDoc) differs. + * `spaceId` value set (documented in JSDoc) differs. + * + * **Preferred form:** pass the `spaceReputation` object (`{ spaceId, + * includeDescendants? }`). The flat props (`spaceReputationId` / + * `spaceReputationDescendants`) are `@deprecated` but still accepted; when both + * forms are supplied the object wins. The object is normalized to the flat wire + * params by `buildSpaceReputationParams` before it reaches the request — it must + * never be forwarded to axios `params` un-normalized (axios would bracket-encode + * it and the server would ignore it). */ /** @@ -22,6 +30,21 @@ */ export interface SpaceReputationContextParams { /** + * Opt the returned/embedded user(s) into a space-scoped `spaceReputation`. + * Accepted `spaceId` forms: + * - a space `` — reputation scoped to that specific space + * - `"none"` — the user's global, non-space reputation + * - `"context"` — reputation scoped to each row's own space (per-row) + * + * `includeDescendants` includes reputation accrued in descendant spaces; only + * honored when `spaceId` is an explicit ``. + */ + spaceReputation?: { + spaceId: string | "none" | "context"; + includeDescendants?: boolean; + }; + /** + * @deprecated Pass `spaceReputation` instead. Retained for back-compat. * Opt the returned/embedded user(s) into a space-scoped `spaceReputation`. * Accepted forms: * - a space `` — reputation scoped to that specific space @@ -30,8 +53,9 @@ export interface SpaceReputationContextParams { */ spaceReputationId?: string; /** - * Include reputation accrued in descendant spaces. Only honored when - * `spaceReputationId` is an explicit ``; ignored for `"none"` and + * @deprecated Pass `spaceReputation.includeDescendants` instead. Retained for + * back-compat. Include reputation accrued in descendant spaces. Only honored + * when `spaceReputationId` is an explicit ``; ignored for `"none"` and * disallowed (not applicable) with `"context"`. */ spaceReputationDescendants?: boolean; @@ -46,17 +70,32 @@ export interface SpaceReputationContextParams { export interface SpaceReputationUserParams { /** * Opt the returned user(s) into a space-scoped `spaceReputation`. - * Accepted forms: + * Accepted `spaceId` forms: * - a space `` — reputation scoped to that specific space * - `"none"` — the user's global, non-space reputation * * Note: `"context"` is rejected by the server (400) on user-direct routes; * pass an explicit `` or `"none"` here. + * + * `includeDescendants` includes reputation accrued in descendant spaces; only + * honored when `spaceId` is an explicit ``. + */ + spaceReputation?: { + spaceId: string | "none"; + includeDescendants?: boolean; + }; + /** + * @deprecated Pass `spaceReputation` instead. Retained for back-compat. + * Opt the returned user(s) into a space-scoped `spaceReputation`. + * Accepted forms: + * - a space `` — reputation scoped to that specific space + * - `"none"` — the user's global, non-space reputation */ spaceReputationId?: string; /** - * Include reputation accrued in descendant spaces. Only honored when - * `spaceReputationId` is an explicit ``; ignored for `"none"`. + * @deprecated Pass `spaceReputation.includeDescendants` instead. Retained for + * back-compat. Include reputation accrued in descendant spaces. Only honored + * when `spaceReputationId` is an explicit ``; ignored for `"none"`. */ spaceReputationDescendants?: boolean; } diff --git a/src/modules/chat/getMessage.ts b/src/modules/chat/getMessage.ts index c660603..99f6228 100644 --- a/src/modules/chat/getMessage.ts +++ b/src/modules/chat/getMessage.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { ChatMessage } from "../../interfaces/ChatMessage"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface GetMessageProps extends SpaceReputationContextParams { conversationId: string; @@ -13,10 +14,26 @@ export async function getMessage( client: SublayHttpClient, data: GetMessageProps ): Promise { - const { conversationId, messageId, ...params } = data; + const { + conversationId, + messageId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get( `/chat/conversations/${conversationId}/messages/${messageId}`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/chat/listMembers.ts b/src/modules/chat/listMembers.ts index 0c38180..13f06af 100644 --- a/src/modules/chat/listMembers.ts +++ b/src/modules/chat/listMembers.ts @@ -2,6 +2,7 @@ import { SublayHttpClient } from "../../core/client"; import { ConversationMember } from "../../interfaces/ConversationMember"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface ListMembersProps extends SpaceReputationContextParams { conversationId: string; @@ -16,9 +17,24 @@ export async function listMembers( client: SublayHttpClient, data: ListMembersProps ): Promise> { - const { conversationId, ...params } = data; + const { + conversationId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get< PaginatedResponse - >(`/chat/conversations/${conversationId}/members`, { params }); + >(`/chat/conversations/${conversationId}/members`, { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + }); return response.data; } diff --git a/src/modules/chat/listMessages.ts b/src/modules/chat/listMessages.ts index a4051ff..98149f3 100644 --- a/src/modules/chat/listMessages.ts +++ b/src/modules/chat/listMessages.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { ChatMessage } from "../../interfaces/ChatMessage"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface MessageFilters { /** @@ -46,10 +47,25 @@ export async function listMessages( client: SublayHttpClient, data: ListMessagesProps ): Promise { - const { conversationId, ...params } = data; + const { + conversationId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get( `/chat/conversations/${conversationId}/messages`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/chat/listReactions.ts b/src/modules/chat/listReactions.ts index 818ba68..c7b6e21 100644 --- a/src/modules/chat/listReactions.ts +++ b/src/modules/chat/listReactions.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { User } from "../../interfaces/User"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; import { PaginationMetadata } from "../../interfaces/IPaginatedResponse"; export interface ListReactionsProps extends SpaceReputationContextParams { @@ -29,10 +30,26 @@ export async function listReactions( client: SublayHttpClient, data: ListReactionsProps ): Promise { - const { conversationId, messageId, ...params } = data; + const { + conversationId, + messageId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get( `/chat/conversations/${conversationId}/messages/${messageId}/reactions`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/chat/sendMessage.ts b/src/modules/chat/sendMessage.ts index 1ac915c..59b04cc 100644 --- a/src/modules/chat/sendMessage.ts +++ b/src/modules/chat/sendMessage.ts @@ -4,6 +4,7 @@ import { ChatMessage } from "../../interfaces/ChatMessage"; import { GifData } from "../../interfaces/Comment"; import { Mention } from "../../interfaces/Mention"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface ChatMessageFile { file: Uint8Array | Blob; @@ -34,6 +35,7 @@ export async function sendMessage( const { conversationId, files, + spaceReputation, spaceReputationId, spaceReputationDescendants, ...body @@ -42,7 +44,11 @@ export async function sendMessage( // Space-reputation opts go as query params (never body fields), so they // travel the same way for both the JSON and multipart variants. - const params = { spaceReputationId, spaceReputationDescendants }; + const params = buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }); // With attachments, send multipart: object fields are JSON-stringified (the // server parses them back) and the files are appended. Otherwise send JSON. diff --git a/src/modules/comments/fetchComment.ts b/src/modules/comments/fetchComment.ts index 09a88c5..eb531f5 100644 --- a/src/modules/comments/fetchComment.ts +++ b/src/modules/comments/fetchComment.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { Comment } from "../../interfaces/Comment"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchCommentProps extends SpaceReputationContextParams { commentId: string; @@ -11,10 +12,25 @@ export async function fetchComment( client: SublayHttpClient, data: FetchCommentProps ): Promise { - const { commentId, ...params } = data; + const { + commentId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get( `/comments/${commentId}`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/comments/fetchManyComments.ts b/src/modules/comments/fetchManyComments.ts index 0e6b117..9a3e82d 100644 --- a/src/modules/comments/fetchManyComments.ts +++ b/src/modules/comments/fetchManyComments.ts @@ -2,6 +2,7 @@ import { SublayHttpClient } from "../../core/client"; import { Comment } from "../../interfaces/Comment"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchManyCommentsProps extends SpaceReputationContextParams { entityId?: string; @@ -31,9 +32,20 @@ export async function fetchManyComments( client: SublayHttpClient, data: FetchManyCommentsProps ): Promise> { + const { spaceReputation, spaceReputationId, spaceReputationDescendants, ...rest } = + data; const response = await client.projectInstance.get>( "/comments", - { params: data } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/comments/fetchReactions.ts b/src/modules/comments/fetchReactions.ts index 75d45c2..10aafa9 100644 --- a/src/modules/comments/fetchReactions.ts +++ b/src/modules/comments/fetchReactions.ts @@ -2,6 +2,7 @@ import { SublayHttpClient } from "../../core/client"; import { Reaction, ReactionType } from "../../interfaces/Reaction"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchCommentReactionsProps extends SpaceReputationContextParams { @@ -16,10 +17,25 @@ export async function fetchReactions( client: SublayHttpClient, data: FetchCommentReactionsProps ): Promise> { - const { commentId, ...params } = data; + const { + commentId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get>( `/comments/${commentId}/reactions`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/entities/fetchEntity.ts b/src/modules/entities/fetchEntity.ts index ddafe31..4e51738 100644 --- a/src/modules/entities/fetchEntity.ts +++ b/src/modules/entities/fetchEntity.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { Entity } from "../../interfaces/Entity"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchEntityProps extends SpaceReputationContextParams { entityId: string; @@ -11,10 +12,25 @@ export async function fetchEntity( client: SublayHttpClient, data: FetchEntityProps ): Promise { - const { entityId, ...params } = data; + const { + entityId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get( `/entities/${entityId}`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/entities/fetchManyEntities.ts b/src/modules/entities/fetchManyEntities.ts index 9e51d58..eb617ef 100644 --- a/src/modules/entities/fetchManyEntities.ts +++ b/src/modules/entities/fetchManyEntities.ts @@ -2,6 +2,7 @@ import { SublayHttpClient } from "../../core/client"; import { Entity } from "../../interfaces/Entity"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface KeywordsFilters { includes?: string[]; @@ -99,10 +100,19 @@ export async function fetchManyEntities( data: FetchManyEntitiesProps ): Promise> { const path = `/entities`; + const { spaceReputation, spaceReputationId, spaceReputationDescendants, ...rest } = + data; const response = await client.projectInstance.get>( path, { - params: data, + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, } ); return response.data; diff --git a/src/modules/entities/fetchReactions.ts b/src/modules/entities/fetchReactions.ts index 0eb3f9c..ecf19d9 100644 --- a/src/modules/entities/fetchReactions.ts +++ b/src/modules/entities/fetchReactions.ts @@ -2,6 +2,7 @@ import { SublayHttpClient } from "../../core/client"; import { Reaction, ReactionType } from "../../interfaces/Reaction"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchEntityReactionsProps extends SpaceReputationContextParams { entityId: string; @@ -15,10 +16,25 @@ export async function fetchReactions( client: SublayHttpClient, data: FetchEntityReactionsProps ): Promise> { - const { entityId, ...params } = data; + const { + entityId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get>( `/entities/${entityId}/reactions`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/reports/fetchModeratedReports.ts b/src/modules/reports/fetchModeratedReports.ts index 16a2306..2b5de48 100644 --- a/src/modules/reports/fetchModeratedReports.ts +++ b/src/modules/reports/fetchModeratedReports.ts @@ -2,6 +2,7 @@ import { SublayHttpClient } from "../../core/client"; import { Report, ReportStatus, ReportTargetType } from "../../interfaces/Report"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchModeratedReportsProps extends SpaceReputationContextParams { @@ -18,9 +19,20 @@ export async function fetchModeratedReports( client: SublayHttpClient, data: FetchModeratedReportsProps ): Promise> { + const { spaceReputation, spaceReputationId, spaceReputationDescendants, ...rest } = + data; const response = await client.projectInstance.get>( "/reports/moderated", - { params: data } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/search/askContent.ts b/src/modules/search/askContent.ts index cdbf41e..39d3601 100644 --- a/src/modules/search/askContent.ts +++ b/src/modules/search/askContent.ts @@ -1,5 +1,6 @@ import { SublayHttpClient } from "../../core/client"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface AskContentProps extends SpaceReputationContextParams { query: string; @@ -24,11 +25,18 @@ export async function askContent( client: SublayHttpClient, data: AskContentProps ): Promise { - const { spaceReputationId, spaceReputationDescendants, ...body } = data; + const { spaceReputation, spaceReputationId, spaceReputationDescendants, ...body } = + data; const response = await client.projectInstance.post( "/search/ask", body, - { params: { spaceReputationId, spaceReputationDescendants } } + { + params: buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + } ); return response.data; } diff --git a/src/modules/search/searchContent.ts b/src/modules/search/searchContent.ts index 7ff39fe..9f4cf45 100644 --- a/src/modules/search/searchContent.ts +++ b/src/modules/search/searchContent.ts @@ -2,6 +2,7 @@ import { SublayHttpClient } from "../../core/client"; import { Entity } from "../../interfaces/Entity"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface SearchContentProps extends SpaceReputationContextParams { query: string; @@ -21,11 +22,18 @@ export async function searchContent( client: SublayHttpClient, data: SearchContentProps ): Promise> { - const { spaceReputationId, spaceReputationDescendants, ...body } = data; + const { spaceReputation, spaceReputationId, spaceReputationDescendants, ...body } = + data; const response = await client.projectInstance.post>( "/search/content", body, - { params: { spaceReputationId, spaceReputationDescendants } } + { + params: buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + } ); return response.data; } diff --git a/src/modules/spaces/fetchSpaceMembers.ts b/src/modules/spaces/fetchSpaceMembers.ts index c051758..c778e3e 100644 --- a/src/modules/spaces/fetchSpaceMembers.ts +++ b/src/modules/spaces/fetchSpaceMembers.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { SpaceMembersResponse } from "../../interfaces/SpaceMember"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchSpaceMembersProps extends SpaceReputationContextParams { spaceId: string; @@ -14,10 +15,25 @@ export async function fetchSpaceMembers( client: SublayHttpClient, data: FetchSpaceMembersProps ): Promise { - const { spaceId, ...params } = data; + const { + spaceId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get( `/spaces/${spaceId}/members`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/spaces/fetchSpaceTeam.ts b/src/modules/spaces/fetchSpaceTeam.ts index e07fb99..eaa85db 100644 --- a/src/modules/spaces/fetchSpaceTeam.ts +++ b/src/modules/spaces/fetchSpaceTeam.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { SpaceTeamResponse } from "../../interfaces/SpaceMember"; import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchSpaceTeamProps extends SpaceReputationContextParams { spaceId: string; @@ -10,10 +11,25 @@ export async function fetchSpaceTeam( client: SublayHttpClient, data: FetchSpaceTeamProps ): Promise { - const { spaceId, ...params } = data; + const { + spaceId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get( `/spaces/${spaceId}/team`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/users/fetchConnectionsByUserId.ts b/src/modules/users/fetchConnectionsByUserId.ts index 89c7a2c..0552a2c 100644 --- a/src/modules/users/fetchConnectionsByUserId.ts +++ b/src/modules/users/fetchConnectionsByUserId.ts @@ -2,6 +2,7 @@ import { SublayHttpClient } from "../../core/client"; import { EstablishedConnection } from "../../interfaces/Connection"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; import { SpaceReputationUserParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchConnectionsByUserIdProps extends SpaceReputationUserParams { @@ -14,9 +15,24 @@ export async function fetchConnectionsByUserId( client: SublayHttpClient, data: FetchConnectionsByUserIdProps ): Promise> { - const { userId, ...params } = data; + const { + userId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get< PaginatedResponse - >(`/users/${userId}/connections`, { params }); + >(`/users/${userId}/connections`, { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + }); return response.data; } diff --git a/src/modules/users/fetchFollowersByUserId.ts b/src/modules/users/fetchFollowersByUserId.ts index 14d1216..9e33021 100644 --- a/src/modules/users/fetchFollowersByUserId.ts +++ b/src/modules/users/fetchFollowersByUserId.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { User } from "../../interfaces/User"; import { SpaceReputationUserParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; export interface FetchFollowersByUserIdProps extends SpaceReputationUserParams { @@ -13,10 +14,25 @@ export async function fetchFollowersByUserId( client: SublayHttpClient, data: FetchFollowersByUserIdProps ): Promise> { - const { userId, ...params } = data; + const { + userId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get>( `/users/${userId}/followers`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/users/fetchFollowingByUserId.ts b/src/modules/users/fetchFollowingByUserId.ts index c9823e0..7331065 100644 --- a/src/modules/users/fetchFollowingByUserId.ts +++ b/src/modules/users/fetchFollowingByUserId.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { User } from "../../interfaces/User"; import { SpaceReputationUserParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; import { PaginatedResponse } from "../../interfaces/IPaginatedResponse"; export interface FetchFollowingByUserIdProps extends SpaceReputationUserParams { @@ -13,10 +14,25 @@ export async function fetchFollowingByUserId( client: SublayHttpClient, data: FetchFollowingByUserIdProps ): Promise> { - const { userId, ...params } = data; + const { + userId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const response = await client.projectInstance.get>( `/users/${userId}/following`, - { params } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; } diff --git a/src/modules/users/fetchUserByForeignId.ts b/src/modules/users/fetchUserByForeignId.ts index c7a03cb..10c9807 100644 --- a/src/modules/users/fetchUserByForeignId.ts +++ b/src/modules/users/fetchUserByForeignId.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { User } from "../../interfaces/User"; import { SpaceReputationUserParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchUserByForeignIdProps extends SpaceReputationUserParams { foreignId: string; @@ -32,8 +33,11 @@ export async function fetchUserByForeignId( ? JSON.stringify(data.secureMetadata) : undefined, include: data.include, - spaceReputationId: data.spaceReputationId, - spaceReputationDescendants: data.spaceReputationDescendants, + ...buildSpaceReputationParams({ + spaceReputation: data.spaceReputation, + spaceReputationId: data.spaceReputationId, + spaceReputationDescendants: data.spaceReputationDescendants, + }), }; const response = await client.projectInstance.get(path, { diff --git a/src/modules/users/fetchUserById.ts b/src/modules/users/fetchUserById.ts index 962bb10..cefe244 100644 --- a/src/modules/users/fetchUserById.ts +++ b/src/modules/users/fetchUserById.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { User } from "../../interfaces/User"; import { SpaceReputationUserParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchUserByIdProps extends SpaceReputationUserParams { userId: string; @@ -11,8 +12,23 @@ export async function fetchUserById( client: SublayHttpClient, data: FetchUserByIdProps ): Promise { - const { userId, ...params } = data; + const { + userId, + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + ...rest + } = data; const path = `/users/${userId}`; // assuming client handles prefix like /{projectId} - const response = await client.projectInstance.get(path, { params }); + const response = await client.projectInstance.get(path, { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + }); return response.data; } diff --git a/src/modules/users/fetchUserByUsername.ts b/src/modules/users/fetchUserByUsername.ts index d2ee031..411f66e 100644 --- a/src/modules/users/fetchUserByUsername.ts +++ b/src/modules/users/fetchUserByUsername.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { User } from "../../interfaces/User"; import { SpaceReputationUserParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchUserByUsernameProps extends SpaceReputationUserParams { username: string; @@ -11,8 +12,17 @@ export async function fetchUserByUsername( client: SublayHttpClient, data: FetchUserByUsernameProps ): Promise { + const { spaceReputation, spaceReputationId, spaceReputationDescendants, ...rest } = + data; const response = await client.projectInstance.get("/users/by-username", { - params: data, + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, }); return response.data; } diff --git a/src/modules/users/fetchUserSuggestions.ts b/src/modules/users/fetchUserSuggestions.ts index 05814dd..d14b8b0 100644 --- a/src/modules/users/fetchUserSuggestions.ts +++ b/src/modules/users/fetchUserSuggestions.ts @@ -1,6 +1,7 @@ import { SublayHttpClient } from "../../core/client"; import { User } from "../../interfaces/User"; import { SpaceReputationUserParams } from "../../interfaces/SpaceReputation"; +import { buildSpaceReputationParams } from "../../core/spaceReputationParams"; export interface FetchUserSuggestionsProps extends SpaceReputationUserParams { query: string; @@ -10,9 +11,20 @@ export async function fetchUserSuggestions( client: SublayHttpClient, data: FetchUserSuggestionsProps ): Promise { + const { spaceReputation, spaceReputationId, spaceReputationDescendants, ...rest } = + data; const response = await client.projectInstance.get( "/users/suggestions", - { params: data } + { + params: { + ...rest, + ...buildSpaceReputationParams({ + spaceReputation, + spaceReputationId, + spaceReputationDescendants, + }), + }, + } ); return response.data; }