Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions src/clients/inbox-client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { HttpResponse, http } from 'msw'
import { apiUrl } from '../testUtils/msw-handlers'
import { server } from '../testUtils/msw-setup'
import { TEST_API_TOKEN } from '../testUtils/test-defaults'
import { InboxClient } from './inbox-client'

describe('InboxClient', () => {
let client: InboxClient

beforeEach(() => {
client = new InboxClient({ apiToken: TEST_API_TOKEN })
})

describe('getInbox', () => {
it('should send newerThan as newer_than_ts query parameter', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.get(apiUrl('api/v3/inbox/get'), ({ request }) => {
const url = new URL(request.url)
expect(url.searchParams.get('newer_than_ts')).toBe(String(expectedTs))
expect(url.searchParams.get('workspace_id')).toBe('123')
return HttpResponse.json([])
}),
)

await client.getInbox({ workspaceId: 123, newerThan: date })
})

it('should send olderThan as older_than_ts query parameter', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.get(apiUrl('api/v3/inbox/get'), ({ request }) => {
const url = new URL(request.url)
expect(url.searchParams.get('older_than_ts')).toBe(String(expectedTs))
expect(url.searchParams.get('workspace_id')).toBe('123')
return HttpResponse.json([])
}),
)

await client.getInbox({ workspaceId: 123, olderThan: date })
})

it('should support deprecated since param as newer_than_ts', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.get(apiUrl('api/v3/inbox/get'), ({ request }) => {
const url = new URL(request.url)
expect(url.searchParams.get('newer_than_ts')).toBe(String(expectedTs))
expect(url.searchParams.get('workspace_id')).toBe('123')
return HttpResponse.json([])
}),
)

await client.getInbox({ workspaceId: 123, since: date })
})

it('should support deprecated until param as older_than_ts', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.get(apiUrl('api/v3/inbox/get'), ({ request }) => {
const url = new URL(request.url)
expect(url.searchParams.get('older_than_ts')).toBe(String(expectedTs))
expect(url.searchParams.get('workspace_id')).toBe('123')
return HttpResponse.json([])
}),
)

await client.getInbox({ workspaceId: 123, until: date })
})
})

describe('archiveAll', () => {
it('should send newerThan as since_ts_or_obj_idx parameter', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.post(apiUrl('api/v3/inbox/archive_all'), async ({ request }) => {
const body = await request.json()
expect(body).toEqual({
workspace_id: 123,
since_ts_or_obj_idx: expectedTs,
})
return HttpResponse.json(null)
}),
)

await client.archiveAll({ workspaceId: 123, newerThan: date })
})

it('should send olderThan as until_ts_or_obj_idx parameter', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.post(apiUrl('api/v3/inbox/archive_all'), async ({ request }) => {
const body = await request.json()
expect(body).toEqual({
workspace_id: 123,
until_ts_or_obj_idx: expectedTs,
})
return HttpResponse.json(null)
}),
)

await client.archiveAll({ workspaceId: 123, olderThan: date })
})

it('should support deprecated since param', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.post(apiUrl('api/v3/inbox/archive_all'), async ({ request }) => {
const body = await request.json()
expect(body).toEqual({
workspace_id: 123,
since_ts_or_obj_idx: expectedTs,
})
return HttpResponse.json(null)
}),
)

await client.archiveAll({ workspaceId: 123, since: date })
})
})
})
28 changes: 18 additions & 10 deletions src/clients/inbox-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ export class InboxClient extends BaseClient {
*
* @param args - The arguments for getting inbox.
* @param args.workspaceId - The workspace ID.
* @param args.since - Optional date to get items since.
* @param args.until - Optional date to get items until.
* @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 options - Optional configuration. Set `batch: true` to return a descriptor for batch requests.
Expand All @@ -31,7 +33,7 @@ export class InboxClient extends BaseClient {
* ```typescript
* const inbox = await api.inbox.getInbox({
* workspaceId: 123,
* since: new Date('2024-01-01')
* newerThan: new Date('2024-01-01')
* })
* ```
*/
Expand All @@ -45,8 +47,10 @@ export class InboxClient extends BaseClient {
workspace_id: args.workspaceId,
}

if (args.since) params.newer_than_ts = Math.floor(args.since.getTime() / 1000)
if (args.until) params.older_than_ts = Math.floor(args.until.getTime() / 1000)
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.limit) params.limit = args.limit
if (args.cursor) params.cursor = args.cursor

Expand Down Expand Up @@ -215,15 +219,17 @@ export class InboxClient extends BaseClient {
* @param args - The arguments for archiving all.
* @param args.workspaceId - The workspace ID.
* @param args.channelIds - Optional array of channel IDs to filter by.
* @param args.since - Optional date to filter items since.
* @param args.until - Optional date to filter items until.
* @param args.newerThan - Optional date to filter items newer than.
* @param args.olderThan - Optional date to filter items older than.
* @param args.since - @deprecated Use `newerThan` instead.
* @param args.until - @deprecated Use `olderThan` instead.
* @param options - Optional configuration. Set `batch: true` to return a descriptor for batch requests.
*
* @example
* ```typescript
* await api.inbox.archiveAll({
* workspaceId: 123,
* since: new Date('2024-01-01')
* newerThan: new Date('2024-01-01')
* })
* ```
*/
Expand All @@ -238,8 +244,10 @@ export class InboxClient extends BaseClient {
}

if (args.channelIds) params.channel_ids = args.channelIds
if (args.since) params.since_ts_or_obj_idx = Math.floor(args.since.getTime() / 1000)
if (args.until) params.until_ts_or_obj_idx = Math.floor(args.until.getTime() / 1000)
const newerThan = args.newerThan ?? args.since
if (newerThan) params.since_ts_or_obj_idx = Math.floor(newerThan.getTime() / 1000)
const olderThan = args.olderThan ?? args.until
if (olderThan) params.until_ts_or_obj_idx = Math.floor(olderThan.getTime() / 1000)

const method = 'POST'
const url = `${ENDPOINT_INBOX}/archive_all`
Expand Down
34 changes: 34 additions & 0 deletions src/clients/threads-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,40 @@ describe('ThreadsClient', () => {
client = new ThreadsClient({ apiToken: TEST_API_TOKEN })
})

describe('getThreads', () => {
it('should send newerThan as newer_than_ts query parameter', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.get(apiUrl('api/v3/threads/get'), ({ request }) => {
const url = new URL(request.url)
expect(url.searchParams.get('newer_than_ts')).toBe(String(expectedTs))
expect(url.searchParams.get('workspace_id')).toBe('1')
return HttpResponse.json([])
}),
)

await client.getThreads({ workspaceId: 1, newerThan: date })
})

it('should send olderThan as older_than_ts query parameter', async () => {
const date = new Date('2024-06-15T12:00:00Z')
const expectedTs = Math.floor(date.getTime() / 1000)

server.use(
http.get(apiUrl('api/v3/threads/get'), ({ request }) => {
const url = new URL(request.url)
expect(url.searchParams.get('older_than_ts')).toBe(String(expectedTs))
expect(url.searchParams.get('workspace_id')).toBe('1')
return HttpResponse.json([])
}),
)

await client.getThreads({ workspaceId: 1, olderThan: date })
})
})

describe('pinThread', () => {
it('should pin a thread', async () => {
server.use(
Expand Down
14 changes: 11 additions & 3 deletions src/clients/threads-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export class ThreadsClient extends BaseClient {
* @param args.channelId - The channel ID.
* @param args.workspaceId - Optional workspace ID.
* @param args.archived - Optional flag to include archived threads.
* @param args.newer_than_ts - Optional timestamp to get threads newer than.
* @param args.older_than_ts - Optional timestamp to get threads older than.
* @param args.newerThan - Optional date to get threads newer than.
* @param args.olderThan - Optional date to get threads older than.
* @param args.limit - Optional limit on number of threads returned.
* @param options - Optional configuration. Set `batch: true` to return a descriptor for batch requests.
* @returns An array of thread objects.
Expand All @@ -56,7 +56,15 @@ export class ThreadsClient extends BaseClient {
): Promise<Thread[]> | BatchRequestDescriptor<Thread[]> {
const method = 'GET'
const url = `${ENDPOINT_THREADS}/get`
const params = args
const params: Record<string, unknown> = {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Rebuilding params from scratch here drops the previously documented newer_than_ts / older_than_ts inputs for getThreads(). Before this change, those snake_case keys were forwarded through request() and worked for JS consumers; after this refactor they are silently ignored, so existing calls can start returning unfiltered threads. Please add a deprecated fallback for the old keys, similar to the inbox/comments migrations, before removing that runtime path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 639ff5a. Switched back to the passthrough pattern — we now destructure only the timestamp fields and spread ...rest through. Added deprecated newerThanTs/olderThanTs number fields on GetThreadsArgs (which auto-convert to newer_than_ts/older_than_ts via snakeCaseKeys), with newerThan Date taking precedence when both are provided.

workspace_id: args.workspaceId,
}

if (args.channelId != null) params.channel_id = args.channelId
if (args.archived != null) params.archived = args.archived
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] This truthy check means the new limit support silently ignores an explicit 0. GetThreadsArgsSchema now accepts any number, so callers can pass 0 and get a full result set instead of either limit=0 or a validation error. Using args.limit != null here, or tightening the schema to positive integers, would keep the implementation aligned with the public contract.


if (options?.batch) {
return { method, url, params, schema: z.array(ThreadSchema) }
Expand Down
11 changes: 11 additions & 0 deletions src/types/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ export const GetThreadsArgsSchema = z.object({
workspaceId: z.number(),
channelId: z.number().nullable().optional(),
archived: z.boolean().nullable().optional(),
newerThan: z.date().nullable().optional(),
olderThan: z.date().nullable().optional(),
limit: z.number().nullable().optional(),
})

export type GetThreadsArgs = z.infer<typeof GetThreadsArgsSchema>
Expand Down Expand Up @@ -214,7 +217,11 @@ export type UpdateConversationMessageArgs = {
// Inbox
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
Expand All @@ -223,7 +230,11 @@ export type GetInboxArgs = {
export type ArchiveAllArgs = {
workspaceId: number
channelIds?: number[]
newerThan?: Date
olderThan?: Date
/** @deprecated Use `newerThan` instead. */
since?: Date
/** @deprecated Use `olderThan` instead. */
until?: Date
}

Expand Down
Loading