diff --git a/src/clients/comments-client.ts b/src/clients/comments-client.ts index 21d929a..bfab80d 100644 --- a/src/clients/comments-client.ts +++ b/src/clients/comments-client.ts @@ -25,7 +25,6 @@ export class CommentsClient extends BaseClient { * * @param args - The arguments for getting comments. * @param args.threadId - The thread ID. - * @param args.from - @deprecated Use `newerThan` instead. * @param args.newerThan - Optional date to get comments newer than. * @param args.olderThan - Optional date to get comments older than. * @param args.limit - Optional limit on number of comments returned. @@ -42,8 +41,7 @@ export class CommentsClient extends BaseClient { */ getComments(args: GetCommentsArgs): Promise { const params: Record = { threadId: args.threadId } - const newerThan = args.newerThan ?? args.from - if (newerThan) params.newerThanTs = Math.floor(newerThan.getTime() / 1000) + if (args.newerThan) params.newerThanTs = Math.floor(args.newerThan.getTime() / 1000) if (args.olderThan) params.olderThanTs = Math.floor(args.olderThan.getTime() / 1000) if (args.limit) params.limit = args.limit diff --git a/src/clients/inbox-client.test.ts b/src/clients/inbox-client.test.ts new file mode 100644 index 0000000..c192b59 --- /dev/null +++ b/src/clients/inbox-client.test.ts @@ -0,0 +1,63 @@ +import { http, HttpResponse } from 'msw' +import { describe, expect, it } from 'vitest' +import { CommsApi } from '../comms-api' +import { server } from '../testUtils/msw-setup' +import { TEST_API_BASE_URL as BASE, TEST_API_TOKEN } from '../testUtils/test-defaults' + +// Pins the wire shape of `inbox-client` after the deprecated `since` / +// `until` aliases were dropped — both serialization paths (URL params +// for `getInbox`, body for `archiveAll`) need explicit coverage. + +describe('InboxClient — wire serialization', () => { + it('getInbox sends workspace_id / newer_than_ts / older_than_ts on the URL', async () => { + const capturedUrls: URL[] = [] + server.use( + http.get(`${BASE}/inbox/get`, ({ request }) => { + capturedUrls.push(new URL(request.url)) + return HttpResponse.json([]) + }), + ) + + const api = new CommsApi(TEST_API_TOKEN) + await api.inbox.getInbox({ + workspaceId: 1, + newerThan: new Date('2026-01-01T00:00:00Z'), + olderThan: new Date('2026-02-01T00:00:00Z'), + limit: 25, + archiveFilter: 'all', + }) + + expect(capturedUrls).toHaveLength(1) + const params = (capturedUrls[0] as URL).searchParams + expect(params.get('workspace_id')).toBe('1') + expect(params.get('newer_than_ts')).toBe( + String(Math.floor(new Date('2026-01-01T00:00:00Z').getTime() / 1000)), + ) + expect(params.get('older_than_ts')).toBe( + String(Math.floor(new Date('2026-02-01T00:00:00Z').getTime() / 1000)), + ) + expect(params.get('limit')).toBe('25') + expect(params.get('archive_filter')).toBe('all') + }) + + it('archiveAll POSTs workspace_id and older_than_ts as snake_case', async () => { + let capturedBody: Record | null = null + server.use( + http.post(`${BASE}/inbox/archive_all`, async ({ request }) => { + capturedBody = (await request.json()) as Record + return HttpResponse.json({ status: 'ok' }) + }), + ) + + const api = new CommsApi(TEST_API_TOKEN) + await api.inbox.archiveAll({ + workspaceId: 1, + olderThan: new Date('2026-02-01T00:00:00Z'), + }) + + expect(capturedBody).toEqual({ + workspace_id: 1, + older_than_ts: Math.floor(new Date('2026-02-01T00:00:00Z').getTime() / 1000), + }) + }) +}) diff --git a/src/clients/inbox-client.ts b/src/clients/inbox-client.ts index 3f96ecd..aec32c2 100644 --- a/src/clients/inbox-client.ts +++ b/src/clients/inbox-client.ts @@ -18,8 +18,6 @@ export class InboxClient extends BaseClient { * @param args.workspaceId - The workspace ID. * @param args.newerThan - Optional date to get items newer than. * @param args.olderThan - Optional date to get items older than. - * @param args.since - @deprecated Use `newerThan` instead. - * @param args.until - @deprecated Use `olderThan` instead. * @param args.limit - Optional limit on number of items returned. * @param args.cursor - Optional cursor for pagination. * @param args.archiveFilter - Optional filter: 'active' (default), 'archived', or 'all'. @@ -41,10 +39,8 @@ export class InboxClient extends BaseClient { */ getInbox(args: GetInboxArgs): Promise { const params: Record = { workspace_id: args.workspaceId } - const newerThan = args.newerThan ?? args.since - if (newerThan) params.newer_than_ts = Math.floor(newerThan.getTime() / 1000) - const olderThan = args.olderThan ?? args.until - if (olderThan) params.older_than_ts = Math.floor(olderThan.getTime() / 1000) + if (args.newerThan) params.newer_than_ts = Math.floor(args.newerThan.getTime() / 1000) + if (args.olderThan) params.older_than_ts = Math.floor(args.olderThan.getTime() / 1000) if (args.limit) params.limit = args.limit if (args.cursor) params.cursor = args.cursor if (args.archiveFilter) params.archive_filter = args.archiveFilter @@ -152,8 +148,6 @@ export class InboxClient extends BaseClient { * @param args.workspaceId - The workspace ID. * @param args.channelIds - Optional array of channel IDs to filter by. * @param args.olderThan - Optional date to filter items older than. - * @param args.until - @deprecated Use `olderThan` instead. - * @param args.since - @deprecated Not supported by the archive_all endpoint — this value is ignored. * * @example * ```typescript @@ -166,8 +160,7 @@ export class InboxClient extends BaseClient { archiveAll(args: ArchiveAllArgs): Promise { const params: Record = { workspace_id: args.workspaceId } if (args.channelIds) params.channel_ids = args.channelIds - const olderThan = args.olderThan ?? args.until - if (olderThan) params.older_than_ts = Math.floor(olderThan.getTime() / 1000) + if (args.olderThan) params.older_than_ts = Math.floor(args.olderThan.getTime() / 1000) return request({ httpMethod: 'POST', diff --git a/src/clients/threads-client.test.ts b/src/clients/threads-client.test.ts new file mode 100644 index 0000000..5984a56 --- /dev/null +++ b/src/clients/threads-client.test.ts @@ -0,0 +1,66 @@ +import { http, HttpResponse } from 'msw' +import { describe, expect, it } from 'vitest' +import { CommsApi } from '../comms-api' +import { server } from '../testUtils/msw-setup' +import { TEST_API_BASE_URL as BASE, TEST_API_TOKEN } from '../testUtils/test-defaults' + +// Pins the wire shape of `threads-client`. The PR that dropped the +// `newer_than_ts` / `older_than_ts` aliases also tightened how `params` +// is built — this test catches both a casing regression and any +// accidental forwarding of unknown keys. + +describe('ThreadsClient — wire serialization', () => { + it('getThreads sends workspace_id / channel_id / newer_than_ts / older_than_ts on the URL', async () => { + const capturedUrls: URL[] = [] + server.use( + http.get(`${BASE}/threads/get`, ({ request }) => { + capturedUrls.push(new URL(request.url)) + return HttpResponse.json([]) + }), + ) + + const api = new CommsApi(TEST_API_TOKEN) + await api.threads.getThreads({ + workspaceId: 1, + channelId: '7YpL3oZ4kZ9vP7Q1tR2sX44', + archived: false, + newerThan: new Date('2026-01-01T00:00:00Z'), + olderThan: new Date('2026-02-01T00:00:00Z'), + limit: 50, + }) + + expect(capturedUrls).toHaveLength(1) + const params = (capturedUrls[0] as URL).searchParams + expect(params.get('workspace_id')).toBe('1') + expect(params.get('channel_id')).toBe('7YpL3oZ4kZ9vP7Q1tR2sX44') + expect(params.get('archived')).toBe('false') + expect(params.get('newer_than_ts')).toBe( + String(Math.floor(new Date('2026-01-01T00:00:00Z').getTime() / 1000)), + ) + expect(params.get('older_than_ts')).toBe( + String(Math.floor(new Date('2026-02-01T00:00:00Z').getTime() / 1000)), + ) + expect(params.get('limit')).toBe('50') + }) + + it('getThreads ignores legacy snake_case keys passed at runtime', async () => { + const capturedUrls: URL[] = [] + server.use( + http.get(`${BASE}/threads/get`, ({ request }) => { + capturedUrls.push(new URL(request.url)) + return HttpResponse.json([]) + }), + ) + + const api = new CommsApi(TEST_API_TOKEN) + await api.threads.getThreads({ + workspaceId: 1, + // biome-ignore lint/suspicious/noExplicitAny: legacy-shape forced through `any` + ...({ newer_than_ts: 999, older_than_ts: 888 } as any), + }) + + const params = (capturedUrls[0] as URL).searchParams + expect(params.get('newer_than_ts')).toBeNull() + expect(params.get('older_than_ts')).toBeNull() + }) +}) diff --git a/src/clients/threads-client.ts b/src/clients/threads-client.ts index 3144edd..853b7c4 100644 --- a/src/clients/threads-client.ts +++ b/src/clients/threads-client.ts @@ -51,8 +51,6 @@ export class ThreadsClient extends BaseClient { * @param args.archived - Optional flag to include archived threads. * @param args.newerThan - Optional date to get threads newer than. * @param args.olderThan - Optional date to get threads older than. - * @param args.newer_than_ts - @deprecated Use `newerThan` instead. - * @param args.older_than_ts - @deprecated Use `olderThan` instead. * @param args.limit - Optional limit on number of threads returned. * @returns An array of thread objects. * @@ -66,14 +64,12 @@ export class ThreadsClient extends BaseClient { * ``` */ getThreads(args: GetThreadsArgs): Promise { - const { newerThan, olderThan, newer_than_ts, older_than_ts, ...rest } = args - const resolvedNewerThan = newerThan ? Math.floor(newerThan.getTime() / 1000) : newer_than_ts - const resolvedOlderThan = olderThan ? Math.floor(olderThan.getTime() / 1000) : older_than_ts - const params = { - ...rest, - ...(resolvedNewerThan != null ? { newer_than_ts: resolvedNewerThan } : {}), - ...(resolvedOlderThan != null ? { older_than_ts: resolvedOlderThan } : {}), - } + const params: Record = { workspaceId: args.workspaceId } + if (args.channelId != null) params.channelId = args.channelId + if (args.archived != null) params.archived = args.archived + if (args.limit != null) params.limit = args.limit + if (args.newerThan) params.newer_than_ts = Math.floor(args.newerThan.getTime() / 1000) + if (args.olderThan) params.older_than_ts = Math.floor(args.olderThan.getTime() / 1000) return request({ httpMethod: 'GET', diff --git a/src/types/requests.ts b/src/types/requests.ts index 01f908a..ebd631b 100644 --- a/src/types/requests.ts +++ b/src/types/requests.ts @@ -127,30 +127,16 @@ export const GetThreadsArgsSchema = z.object({ limit: z.number().nullable().optional(), }) -export type GetThreadsArgs = Omit< - z.infer, - 'newerThan' | 'olderThan' -> & { - newerThan?: Date | null - olderThan?: Date | null - /** @deprecated Use `newerThan` instead. */ - newer_than_ts?: number | null - /** @deprecated Use `olderThan` instead. */ - older_than_ts?: number | null -} +export type GetThreadsArgs = z.infer export const GetCommentsArgsSchema = z.object({ threadId: z.string(), - from: z.date().nullable().optional(), newerThan: z.date().nullable().optional(), olderThan: z.date().nullable().optional(), limit: z.number().nullable().optional(), }) -export type GetCommentsArgs = Omit, 'from'> & { - /** @deprecated Use `newerThan` instead. */ - from?: Date | null -} +export type GetCommentsArgs = z.infer export const GetConversationsArgsSchema = z.object({ workspaceId: z.number(), @@ -248,10 +234,6 @@ export type GetInboxArgs = { workspaceId: number newerThan?: Date olderThan?: Date - /** @deprecated Use `newerThan` instead. */ - since?: Date - /** @deprecated Use `olderThan` instead. */ - until?: Date limit?: number cursor?: string archiveFilter?: ArchiveFilter @@ -261,10 +243,6 @@ export type ArchiveAllArgs = { workspaceId: number channelIds?: string[] olderThan?: Date - /** @deprecated Use `olderThan` instead. */ - until?: Date - /** @deprecated Not supported by the archive_all endpoint — this value is ignored. */ - since?: Date } // Reactions.