From 6086e677bc157d620ab63d0f4737509a860e64d3 Mon Sep 17 00:00:00 2001 From: RickjanHoornbeeck <51879@hoornbeeck.nl> Date: Fri, 10 Apr 2026 13:09:42 +0200 Subject: [PATCH 1/5] fix: handle empty responses in HttpHandler --- src/core/http.ts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/core/http.ts b/src/core/http.ts index 9685aff..3bf8ff3 100644 --- a/src/core/http.ts +++ b/src/core/http.ts @@ -24,6 +24,10 @@ export class HttpHandler { readonly #apiKey: string readonly #baseUrl: string + #emptyResponse(): T { + return undefined! + } + constructor(props: ClientProps) { this.#apiKey = props.apiKey this.#baseUrl = props.urlEndpoint ?? DefaultEndpoint @@ -66,16 +70,31 @@ export class HttpHandler { } async #handleResponse(response: Response): Promise { + if (!response.ok) { throw await this.#mapError(response) } + if (response.status === 204 || response.status === 205) { + return this.#emptyResponse() + } + + const contentLength = response.headers.get('content-length') + if (contentLength === '0') { + return this.#emptyResponse() + } + const contentType = response.headers.get('content-type') if (!contentType || !contentType.includes('application/json')) { - return undefined as T + return this.#emptyResponse() + } + + const text = await response.text() + if (!text.trim()) { + return this.#emptyResponse() } - return response.json() as Promise + return JSON.parse(text) } async #mapError(response: Response): Promise { From e45dc87d26cbb98e1fa49a14e0c5ece40b63def1 Mon Sep 17 00:00:00 2001 From: RickjanHoornbeeck <51879@hoornbeeck.nl> Date: Fri, 10 Apr 2026 13:26:57 +0200 Subject: [PATCH 2/5] fix: suggested changes --- src/core/http.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/core/http.ts b/src/core/http.ts index 3bf8ff3..38118e7 100644 --- a/src/core/http.ts +++ b/src/core/http.ts @@ -75,10 +75,6 @@ export class HttpHandler { throw await this.#mapError(response) } - if (response.status === 204 || response.status === 205) { - return this.#emptyResponse() - } - const contentLength = response.headers.get('content-length') if (contentLength === '0') { return this.#emptyResponse() @@ -89,12 +85,7 @@ export class HttpHandler { return this.#emptyResponse() } - const text = await response.text() - if (!text.trim()) { - return this.#emptyResponse() - } - - return JSON.parse(text) + return response.json() } async #mapError(response: Response): Promise { From 2aefecb8b37000a9fbda03a29770220e6bf6dac5 Mon Sep 17 00:00:00 2001 From: IAmKirbki Date: Fri, 10 Apr 2026 14:04:56 +0200 Subject: [PATCH 3/5] fix: add generic type parameters to post and remove methods for better type safety --- src/core/resources/organizations/events.ts | 2 +- src/core/resources/organizations/organization.ts | 8 ++++---- src/core/resources/organizations/scheduled.ts | 4 ++-- src/core/resources/users/events.ts | 2 +- src/core/resources/users/scheduled.ts | 4 ++-- src/core/resources/users/user.ts | 4 ++-- src/platform/browser.ts | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/core/resources/organizations/events.ts b/src/core/resources/organizations/events.ts index 8e7face..d826e5c 100644 --- a/src/core/resources/organizations/events.ts +++ b/src/core/resources/organizations/events.ts @@ -9,6 +9,6 @@ export class OrganizationEventsResource extends BaseResource { * @param data - Array of organization events */ async post(data: OrganizationEvent[]): Promise { - return super.post(data) + return super.post(data) } } diff --git a/src/core/resources/organizations/organization.ts b/src/core/resources/organizations/organization.ts index 19b291a..1537a86 100644 --- a/src/core/resources/organizations/organization.ts +++ b/src/core/resources/organizations/organization.ts @@ -27,7 +27,7 @@ export class OrganizationResource extends BaseResource { * @returns Promise resolving to the created/updated organization */ async upsert(data: OrganizationRequest): Promise { - return this.post(data) + return this.post(data) } /** @@ -36,7 +36,7 @@ export class OrganizationResource extends BaseResource { * @returns Promise resolving when organization is deleted */ async delete(data: DeleteOrganizationRequest): Promise { - return this.remove(data) + return this.remove(data) } /** @@ -45,7 +45,7 @@ export class OrganizationResource extends BaseResource { * @returns Promise resolving when user is added */ async addUser(data: OrganizationUserRequest): Promise { - return this.post(data, 'organizations/users') + return this.post(data, 'organizations/users') } /** @@ -54,6 +54,6 @@ export class OrganizationResource extends BaseResource { * @returns Promise resolving when user is removed */ async removeUser(data: RemoveOrganizationUserRequest): Promise { - return this.remove(data, 'organizations/users') + return this.remove(data, 'organizations/users') } } diff --git a/src/core/resources/organizations/scheduled.ts b/src/core/resources/organizations/scheduled.ts index af2f77d..031c5d5 100644 --- a/src/core/resources/organizations/scheduled.ts +++ b/src/core/resources/organizations/scheduled.ts @@ -17,7 +17,7 @@ export class OrganizationScheduledResource extends BaseResource { * @returns Promise resolving to the accepted scheduled resource */ async upsert(data: UpsertOrganizationScheduledRequest): Promise { - return this.post(data) + return this.post(data) } /** @@ -26,6 +26,6 @@ export class OrganizationScheduledResource extends BaseResource { * @returns Promise resolving when scheduled resource is deleted */ async delete(data: DeleteOrganizationScheduledRequest): Promise { - return this.remove(data) + return this.remove(data) } } diff --git a/src/core/resources/users/events.ts b/src/core/resources/users/events.ts index 39c3c48..a38fa4a 100644 --- a/src/core/resources/users/events.ts +++ b/src/core/resources/users/events.ts @@ -9,6 +9,6 @@ export class UserEventsResource extends BaseResource { * @param data - Array of user events */ async post(data: UserEvent[]): Promise { - return super.post(data) + return super.post(data) } } diff --git a/src/core/resources/users/scheduled.ts b/src/core/resources/users/scheduled.ts index bc033af..cae569d 100644 --- a/src/core/resources/users/scheduled.ts +++ b/src/core/resources/users/scheduled.ts @@ -17,7 +17,7 @@ export class UserScheduledResource extends BaseResource { * @returns Promise resolving to the accepted scheduled resource */ async upsert(data: UpsertUserScheduledRequest): Promise { - return this.post(data) + return this.post(data) } /** @@ -26,6 +26,6 @@ export class UserScheduledResource extends BaseResource { * @returns Promise resolving when scheduled resource is deleted */ async delete(data: DeleteUserScheduledRequest): Promise { - return this.remove(data) + return this.remove(data) } } diff --git a/src/core/resources/users/user.ts b/src/core/resources/users/user.ts index 5af36fb..1a903b4 100644 --- a/src/core/resources/users/user.ts +++ b/src/core/resources/users/user.ts @@ -25,7 +25,7 @@ export class UserResource extends BaseResource { * @returns Promise resolving to the created/updated user */ async upsert(data: UpsertUserRequest): Promise { - return this.post(data) + return this.post(data) } /** @@ -34,6 +34,6 @@ export class UserResource extends BaseResource { * @returns Promise resolving when user is deleted */ async delete(data: DeleteUserRequest): Promise { - return this.remove(data) + return this.remove(data) } } diff --git a/src/platform/browser.ts b/src/platform/browser.ts index 99e068c..3f66831 100644 --- a/src/platform/browser.ts +++ b/src/platform/browser.ts @@ -31,7 +31,7 @@ class BrowserUserEventsResource extends UserEventsResource { // Do not inject identifier when `match` is used (they are mutually exclusive) identifier: event.match ? event.identifier : (event.identifier ?? identifier), })) - return super.post(injected) as Promise + return super.post(injected) } } From 2aa90650b25638d0b9c52d054614d3c1467b7685 Mon Sep 17 00:00:00 2001 From: RickjanHoornbeeck <51879@hoornbeeck.nl> Date: Fri, 10 Apr 2026 14:27:27 +0200 Subject: [PATCH 4/5] fix: some cleanup done --- src/core/http.ts | 19 +++++++------------ src/core/resources/base.ts | 6 +++--- src/core/resources/organizations/events.ts | 2 +- .../resources/organizations/organization.ts | 2 +- src/core/resources/organizations/scheduled.ts | 2 +- src/core/resources/users/events.ts | 2 +- src/core/resources/users/scheduled.ts | 2 +- src/core/resources/users/user.ts | 2 +- src/platform/browser.ts | 6 +++--- 9 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/core/http.ts b/src/core/http.ts index 38118e7..34817e9 100644 --- a/src/core/http.ts +++ b/src/core/http.ts @@ -24,28 +24,24 @@ export class HttpHandler { readonly #apiKey: string readonly #baseUrl: string - #emptyResponse(): T { - return undefined! - } - constructor(props: ClientProps) { this.#apiKey = props.apiKey this.#baseUrl = props.urlEndpoint ?? DefaultEndpoint } - async get(path: string, data?: unknown): Promise { + async get(path: string, data?: unknown): Promise { return this.#request('GET', path, data) } - async post(path: string, data?: unknown): Promise { + async post(path: string, data?: unknown): Promise { return this.#request('POST', path, data) } - async delete(path: string, data?: unknown): Promise { + async delete(path: string, data?: unknown): Promise { return this.#request('DELETE', path, data) } - async #request(method: HttpMethod, path: string, data?: unknown): Promise { + async #request(method: HttpMethod, path: string, data?: unknown): Promise { const url = `${this.#baseUrl}/client/${path}` try { @@ -69,20 +65,19 @@ export class HttpHandler { } } - async #handleResponse(response: Response): Promise { - + async #handleResponse(response: Response): Promise { if (!response.ok) { throw await this.#mapError(response) } const contentLength = response.headers.get('content-length') if (contentLength === '0') { - return this.#emptyResponse() + return undefined } const contentType = response.headers.get('content-type') if (!contentType || !contentType.includes('application/json')) { - return this.#emptyResponse() + return undefined } return response.json() diff --git a/src/core/resources/base.ts b/src/core/resources/base.ts index 5f418bf..d1c05df 100644 --- a/src/core/resources/base.ts +++ b/src/core/resources/base.ts @@ -9,15 +9,15 @@ export abstract class BaseResource { protected abstract readonly endpoint: string - protected async get(data?: unknown): Promise { + protected async get(data?: unknown): Promise { return this.#http.get(this.endpoint, data) } - protected async post(data?: unknown, pathOverride?: string): Promise { + protected async post(data?: unknown, pathOverride?: string): Promise { return this.#http.post(pathOverride ?? this.endpoint, data) } - protected async remove(data?: unknown, pathOverride?: string): Promise { + protected async remove(data?: unknown, pathOverride?: string): Promise { return this.#http.delete(pathOverride ?? this.endpoint, data) } } diff --git a/src/core/resources/organizations/events.ts b/src/core/resources/organizations/events.ts index d826e5c..6a70c85 100644 --- a/src/core/resources/organizations/events.ts +++ b/src/core/resources/organizations/events.ts @@ -8,7 +8,7 @@ export class OrganizationEventsResource extends BaseResource { * Posts organization events for asynchronous processing. * @param data - Array of organization events */ - async post(data: OrganizationEvent[]): Promise { + async post(data: OrganizationEvent[]): Promise { return super.post(data) } } diff --git a/src/core/resources/organizations/organization.ts b/src/core/resources/organizations/organization.ts index 1537a86..10c370b 100644 --- a/src/core/resources/organizations/organization.ts +++ b/src/core/resources/organizations/organization.ts @@ -26,7 +26,7 @@ export class OrganizationResource extends BaseResource { * @param data - Organization data including identifier, name, data, etc. * @returns Promise resolving to the created/updated organization */ - async upsert(data: OrganizationRequest): Promise { + async upsert(data: OrganizationRequest): Promise { return this.post(data) } diff --git a/src/core/resources/organizations/scheduled.ts b/src/core/resources/organizations/scheduled.ts index 031c5d5..97d7f1f 100644 --- a/src/core/resources/organizations/scheduled.ts +++ b/src/core/resources/organizations/scheduled.ts @@ -16,7 +16,7 @@ export class OrganizationScheduledResource extends BaseResource { * @param data - Scheduled resource data including name, identifier, scheduledAt, interval, etc. * @returns Promise resolving to the accepted scheduled resource */ - async upsert(data: UpsertOrganizationScheduledRequest): Promise { + async upsert(data: UpsertOrganizationScheduledRequest): Promise { return this.post(data) } diff --git a/src/core/resources/users/events.ts b/src/core/resources/users/events.ts index a38fa4a..31b0d65 100644 --- a/src/core/resources/users/events.ts +++ b/src/core/resources/users/events.ts @@ -8,7 +8,7 @@ export class UserEventsResource extends BaseResource { * Posts user events for asynchronous processing. * @param data - Array of user events */ - async post(data: UserEvent[]): Promise { + async post(data: UserEvent[]): Promise { return super.post(data) } } diff --git a/src/core/resources/users/scheduled.ts b/src/core/resources/users/scheduled.ts index cae569d..a25a597 100644 --- a/src/core/resources/users/scheduled.ts +++ b/src/core/resources/users/scheduled.ts @@ -16,7 +16,7 @@ export class UserScheduledResource extends BaseResource { * @param data - Scheduled resource data including name, identifier, scheduledAt, interval, etc. * @returns Promise resolving to the accepted scheduled resource */ - async upsert(data: UpsertUserScheduledRequest): Promise { + async upsert(data: UpsertUserScheduledRequest): Promise { return this.post(data) } diff --git a/src/core/resources/users/user.ts b/src/core/resources/users/user.ts index 1a903b4..e72abc8 100644 --- a/src/core/resources/users/user.ts +++ b/src/core/resources/users/user.ts @@ -24,7 +24,7 @@ export class UserResource extends BaseResource { * @param data - User data including identifier, email, phone, etc. * @returns Promise resolving to the created/updated user */ - async upsert(data: UpsertUserRequest): Promise { + async upsert(data: UpsertUserRequest): Promise { return this.post(data) } diff --git a/src/platform/browser.ts b/src/platform/browser.ts index 3f66831..91c11e0 100644 --- a/src/platform/browser.ts +++ b/src/platform/browser.ts @@ -24,7 +24,7 @@ class BrowserUserEventsResource extends UserEventsResource { this.#getIdentifier = getIdentifier } - async post(data: UserEvent[]): Promise { + async post(data: UserEvent[]): Promise { const identifier = this.#getIdentifier() const injected = data.map((event) => ({ ...event, @@ -43,7 +43,7 @@ class BrowserUserScheduledResource extends UserScheduledResource { this.#getIdentifier = getIdentifier } - async upsert(data: UpsertUserScheduledRequest): Promise { + async upsert(data: UpsertUserScheduledRequest): Promise { return super.upsert({ ...data, identifier: data.identifier ?? this.#getIdentifier(), @@ -113,7 +113,7 @@ class BrowserUserResource extends UserResource { return identifier } - async upsert(data: UpsertUserRequest): Promise { + async upsert(data: UpsertUserRequest): Promise { const identifier = this.#buildIdentifier(data.identifier) return super.upsert({ ...data, identifier }) } From d87adb5c0c7a42da9092c1ae80578399ac3cdc05 Mon Sep 17 00:00:00 2001 From: RickjanHoornbeeck <51879@hoornbeeck.nl> Date: Thu, 28 May 2026 12:55:29 +0200 Subject: [PATCH 5/5] feat: add inbox endpoints for users and organizations Co-Authored-By: Claude Sonnet 4.6 --- src/core/http.ts | 18 +++++- src/core/resources/base.ts | 4 +- src/core/resources/organizations/inbox.ts | 48 ++++++++++++++ src/core/resources/organizations/index.ts | 3 +- .../resources/organizations/organization.ts | 3 + src/core/resources/users/inbox.ts | 48 ++++++++++++++ src/core/resources/users/index.ts | 3 +- src/core/resources/users/user.ts | 3 + src/types/request.ts | 62 +++++++++++++++++++ 9 files changed, 186 insertions(+), 6 deletions(-) create mode 100644 src/core/resources/organizations/inbox.ts create mode 100644 src/core/resources/users/inbox.ts diff --git a/src/core/http.ts b/src/core/http.ts index 34817e9..8b64c86 100644 --- a/src/core/http.ts +++ b/src/core/http.ts @@ -42,7 +42,21 @@ export class HttpHandler { } async #request(method: HttpMethod, path: string, data?: unknown): Promise { - const url = `${this.#baseUrl}/client/${path}` + let url = `${this.#baseUrl}/client/${path}` + let body: string | undefined + + if (method === 'GET' && data) { + const mapped = mapKeys(data) as Record + const params = new URLSearchParams() + for (const [key, value] of Object.entries(mapped)) { + if (value !== null && value !== undefined) { + params.set(key, String(value)) + } + } + url = `${url}?${params.toString()}` + } else if (data) { + body = JSON.stringify(mapKeys(data)) + } try { const response = await fetch(url, { @@ -51,7 +65,7 @@ export class HttpHandler { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.#apiKey}`, }, - body: data ? JSON.stringify(mapKeys(data)) : undefined, + body, }) return this.#handleResponse(response) diff --git a/src/core/resources/base.ts b/src/core/resources/base.ts index d1c05df..a8162e4 100644 --- a/src/core/resources/base.ts +++ b/src/core/resources/base.ts @@ -9,8 +9,8 @@ export abstract class BaseResource { protected abstract readonly endpoint: string - protected async get(data?: unknown): Promise { - return this.#http.get(this.endpoint, data) + protected async get(data?: unknown, pathOverride?: string): Promise { + return this.#http.get(pathOverride ?? this.endpoint, data) } protected async post(data?: unknown, pathOverride?: string): Promise { diff --git a/src/core/resources/organizations/inbox.ts b/src/core/resources/organizations/inbox.ts new file mode 100644 index 0000000..aef8c0c --- /dev/null +++ b/src/core/resources/organizations/inbox.ts @@ -0,0 +1,48 @@ +import { BaseResource } from '../base' +import { + PostInboxMessagesRequest, + InboxMessageEvents, + GetInboxParams, + GetInboxCountParams, + InboxMessageList, + InboxCount, +} from '../../../types' + +export class OrganizationInboxResource extends BaseResource { + readonly endpoint = 'organizations/inbox' + + /** + * Creates one or more inbox messages for organizations. Processed asynchronously. + */ + async create(data: PostInboxMessagesRequest): Promise { + return super.post(data) + } + + /** + * Returns visible, non-expired inbox messages for an organization. + */ + async list(params: GetInboxParams): Promise { + return super.get(params) + } + + /** + * Returns unread and total inbox message counts for an organization. + */ + async count(params: GetInboxCountParams): Promise { + return super.get(params, 'organizations/inbox/count') + } + + /** + * Marks one or more inbox messages as opened. Processed asynchronously. + */ + async opened(data: InboxMessageEvents): Promise { + return super.post(data, 'organizations/inbox/opened') + } + + /** + * Marks one or more inbox messages as archived. Processed asynchronously. + */ + async archived(data: InboxMessageEvents): Promise { + return super.post(data, 'organizations/inbox/archived') + } +} diff --git a/src/core/resources/organizations/index.ts b/src/core/resources/organizations/index.ts index 237ff2c..50e521b 100644 --- a/src/core/resources/organizations/index.ts +++ b/src/core/resources/organizations/index.ts @@ -1,3 +1,4 @@ export { OrganizationResource } from './organization' export { OrganizationScheduledResource } from './scheduled' -export { OrganizationEventsResource } from './events' \ No newline at end of file +export { OrganizationEventsResource } from './events' +export { OrganizationInboxResource } from './inbox' \ No newline at end of file diff --git a/src/core/resources/organizations/organization.ts b/src/core/resources/organizations/organization.ts index 10c370b..e2d7d09 100644 --- a/src/core/resources/organizations/organization.ts +++ b/src/core/resources/organizations/organization.ts @@ -9,16 +9,19 @@ import { BaseResource } from "../base" import { HttpHandler } from "../../http" import { OrganizationScheduledResource } from "./scheduled" import { OrganizationEventsResource } from "./events" +import { OrganizationInboxResource } from "./inbox" export class OrganizationResource extends BaseResource { readonly endpoint = 'organizations' readonly schedule: OrganizationScheduledResource readonly events: OrganizationEventsResource + readonly inbox: OrganizationInboxResource constructor(http: HttpHandler) { super(http) this.schedule = new OrganizationScheduledResource(http) this.events = new OrganizationEventsResource(http) + this.inbox = new OrganizationInboxResource(http) } /** diff --git a/src/core/resources/users/inbox.ts b/src/core/resources/users/inbox.ts new file mode 100644 index 0000000..0db15a4 --- /dev/null +++ b/src/core/resources/users/inbox.ts @@ -0,0 +1,48 @@ +import { BaseResource } from '../base' +import { + PostInboxMessagesRequest, + InboxMessageEvents, + GetInboxParams, + GetInboxCountParams, + InboxMessageList, + InboxCount, +} from '../../../types' + +export class UserInboxResource extends BaseResource { + readonly endpoint = 'users/inbox' + + /** + * Creates one or more inbox messages for users. Processed asynchronously. + */ + async create(data: PostInboxMessagesRequest): Promise { + return super.post(data) + } + + /** + * Returns visible, non-expired inbox messages for a user. + */ + async list(params: GetInboxParams): Promise { + return super.get(params) + } + + /** + * Returns unread and total inbox message counts for a user. + */ + async count(params: GetInboxCountParams): Promise { + return super.get(params, 'users/inbox/count') + } + + /** + * Marks one or more inbox messages as opened. Processed asynchronously. + */ + async opened(data: InboxMessageEvents): Promise { + return super.post(data, 'users/inbox/opened') + } + + /** + * Marks one or more inbox messages as archived. Processed asynchronously. + */ + async archived(data: InboxMessageEvents): Promise { + return super.post(data, 'users/inbox/archived') + } +} diff --git a/src/core/resources/users/index.ts b/src/core/resources/users/index.ts index aea3ac6..87b65fa 100644 --- a/src/core/resources/users/index.ts +++ b/src/core/resources/users/index.ts @@ -1,3 +1,4 @@ export { UserResource } from './user' export { UserScheduledResource } from './scheduled' -export { UserEventsResource } from './events' \ No newline at end of file +export { UserEventsResource } from './events' +export { UserInboxResource } from './inbox' \ No newline at end of file diff --git a/src/core/resources/users/user.ts b/src/core/resources/users/user.ts index e72abc8..dc3cfe5 100644 --- a/src/core/resources/users/user.ts +++ b/src/core/resources/users/user.ts @@ -7,16 +7,19 @@ import { } from '../../../types' import { UserScheduledResource } from './scheduled' import { UserEventsResource } from './events' +import { UserInboxResource } from './inbox' export class UserResource extends BaseResource { readonly endpoint = 'users' readonly schedule: UserScheduledResource readonly events: UserEventsResource + readonly inbox: UserInboxResource constructor(http: HttpHandler) { super(http) this.schedule = new UserScheduledResource(http) this.events = new UserEventsResource(http) + this.inbox = new UserInboxResource(http) } /** diff --git a/src/types/request.ts b/src/types/request.ts index ee5dd5f..c670506 100644 --- a/src/types/request.ts +++ b/src/types/request.ts @@ -116,6 +116,68 @@ export interface RemoveOrganizationUserRequest { } } +// Inbox types + +export type InboxStatus = 'unread' | 'opened' | 'archived' + +/** Request to create inbox messages */ +export interface PostInboxMessagesRequest { + source: string + externalId: string + messages: Record[] +} + +/** Request to mark inbox messages as opened or archived */ +export interface InboxMessageEvents { + source: string + externalId: string + messageIds: string[] +} + +/** Query params for fetching inbox messages */ +export interface GetInboxParams { + source: string + externalId: string + channel: string + status?: InboxStatus + tags?: string + messageSource?: string + priority?: number + limit?: number + offset?: number +} + +/** Query params for counting inbox messages */ +export interface GetInboxCountParams { + source: string + externalId: string + channel: string +} + +/** A single inbox message as returned by the API */ +export interface InboxMessage { + id: string + data: Record + status: InboxStatus + channel: string + priority: number + tags: string[] + createdAt: string + updatedAt: string +} + +/** Paginated list of inbox messages */ +export interface InboxMessageList { + data: InboxMessage[] + total: number +} + +/** Inbox message counts */ +export interface InboxCount { + unread: number + total: number +} + /** Event data for organization events */ export interface OrganizationEvent { /** Organization identifier array. Mutually exclusive with `match`. */