import type { PublishRequest } from "./client"; import type { Requester } from "./http"; import type { HTTPMethods } from "./types"; import type { MessageCancelFilters } from "./filter-types"; import { assertNonEmptyId, buildBulkActionFilterPayload } from "./utils"; export type Message = { /** * A unique identifier for this message. */ messageId: string; /** * The url group name if this message was sent to a urlGroup. */ urlGroup?: string; /** * Deprecated. The topic name if this message was sent to a urlGroup. Use urlGroup instead */ topicName?: string; /** * The url where this message is sent to. */ url: string; /** * The endpoint name of the message if the endpoint is given a * name within the url group. */ endpointName?: string; /** * The api name if this message was sent to an api */ api?: string; /** * The http method used to deliver the message */ method?: HTTPMethods; /** * The http headers sent along with the message to your API. */ header?: Record; /** * The http body sent to your API */ body?: string; /** * The base64 encoded body if the body contains non-UTF-8 characters, * `None` otherwise. */ bodyBase64?: string; /** * Maxmimum number of retries. */ maxRetries?: number; /** * The retry delay expression for this message, * if retry_delay was set when publishing the message. */ retryDelayExpression?: PublishRequest["retryDelay"]; /** * A unix timestamp (milliseconds) after which this message may get delivered. */ notBefore?: number; /** * A unix timestamp (milliseconds) when this messages was created. */ createdAt: number; /** * The callback url if configured. */ callback?: string; /** * The failure callback url if configured. */ failureCallback?: string; /** * The queue name if this message was sent to a queue. */ queueName?: string; /** * The scheduleId of the message if the message is triggered by a schedule */ scheduleId?: string; /** * IP address of the publisher of this message */ callerIp?: string; /** * flow control key */ flowControlKey: string; /** * number of requests which can be active with the same flow control key */ parallelism?: number; /** * number of requests to activate per second with the same flow control key * * @deprecated use rate instead */ ratePerSecond?: number; /** * number of requests to activate within the period with the same flow control key. * Default period is a second. */ rate?: number; /** * The time interval during which the specified `rate` of requests can be activated * using the same flow control key. * * In seconds. */ period?: number; /** * The label assigned to the message for filtering purposes. * * @deprecated Use `labels` instead. When a message has multiple labels, this * field only contains the first one. */ label?: string; /** * The labels assigned to the message for filtering purposes. * * A message can have multiple labels when published with `label: string[]`. */ labels?: string[]; }; export type MessagePayload = Omit & { topicName: string }; export class Messages { private readonly http: Requester; constructor(http: Requester) { this.http = http; } /** * Get a message */ public async get(messageId: string): Promise { assertNonEmptyId(messageId, "Message id"); const messagePayload = await this.http.request({ method: "GET", path: ["v2", "messages", messageId], }); const message: Message = { ...messagePayload, urlGroup: messagePayload.topicName, ratePerSecond: "rate" in messagePayload ? messagePayload.rate : undefined, }; return message; } /** * Cancel messages. * * Can be called with: * - A single messageId: `cancel("id")` * - An array of messageIds: `cancel(["id1", "id2"])` * - A filter object: `cancel({ filter: { flowControlKey: "key", label: "label" } })` * - All messages: `cancel({ all: true })` * * Filters support multiple values: pass an array to match a message whose value * equals any of the given values (OR logic). Separate filters are combined with * AND logic. For example: * `cancel({ filter: { url: ["https://a.com", "https://b.com"], host: "a.com" } })` * * Pass `count` to limit the number of messages processed per call (defaults to 100). * Call in a loop until `cancelled` is 0: * * ```ts * let cancelled: number; * do { * const result = await messages.cancel({ all: true, count: 100 }); * cancelled = result.cancelled; * } while (cancelled > 0); * ``` */ public async cancel( request: string | string[] | MessageCancelFilters ): Promise<{ cancelled: number }> { // Handle single string separately, for backwards compatibility on the response if (typeof request === "string") { assertNonEmptyId(request, "Message id"); return await this.http.request({ method: "DELETE", path: ["v2", "messages", request], }); } // Early return for empty string[] if (Array.isArray(request) && request.length === 0) return { cancelled: 0 }; const filters: MessageCancelFilters = Array.isArray(request) ? { messageIds: request } : request; return await this.http.request({ method: "DELETE", path: ["v2", "messages"], query: buildBulkActionFilterPayload(filters), }); } /** * Delete a message. * * @deprecated Use `cancel(messageId: string)` instead */ public async delete(messageId: string): Promise { assertNonEmptyId(messageId, "Message id"); await this.http.request({ method: "DELETE", path: ["v2", "messages", messageId], parseResponseAsJson: false, }); } /** * Cancel multiple messages by their messageIds. * * @deprecated Use `cancel(messageIds: string[])` instead */ public async deleteMany(messageIds: string[]): Promise { const result = await this.cancel(messageIds); return result.cancelled; } /** * Cancel all messages * @deprecated Use `cancel({all: true})` to cancel all */ public async deleteAll(): Promise { const result = await this.cancel({ all: true }); return result.cancelled; } }